11.3 Пример: генератор псевдослучайной последовательности
==770
Самый быстрый способ изучения того, как какая-то идея может выглядеть при разных способах реализации - посмотреть примеры. Предлагаемый к реализации проект - «генератор бреда» 11 - схема, которая выдаёт наружу псевдослучайные данные в виде последовательных 8-разрядных слов через стандартный асинхронный порт RS-232. Сначала будет разобрана конструкция , затем показана принципиальная схема, собранная
- на жёсткой логике ,
- на программируемых логических схемах с использованием двух популярных методов задания проектного файла: схемного ввода и текста на языке описания аппаратуры 12 ,
- наконец, посмотрим, как та же задача решается на микроконтроллере .
Микроконтроллер - недорогой ( и незаменимый ) однокристальный компьютер, прямо предназначенный для «встраивания» в электронные приборы и имеющем в своём распоряжении память и периферийные устройства. Сами микроконтроллеры рассматриваются в Части 15 , но трудно удержаться от показа их возможностей, просто потому что это достаточно привлекательная альтернатива.
==771
Часть завершается разделом с советами, какие компоненты использовать, как работать с программными инструментами с аргументацией за и против.
11.3.1 Как получают псевдослучайные данные
В §13.14 описывается простой метод получения псевдослучайных битовых последовательностей ( PRBS ) на сдвиговых регистрах, на вход которых поступает результат операции «ИСКЛЮЧАЮЩЕЕ-ИЛИ» двух и более промежуточных разрядов 13 . Итоговая последовательность является псевдослучайной , потому что, хотя и имеет многие признаки чисто случайной, таковой не является и, более того, полностью предопределена и имеет интервал повторения 2n-1 для регистра длиной n разрядов 14 .
В примере будет использоваться регистр длиной 31 ( рис. 11.7 ), для которого «ИСКЛЮЧАЮЩЕЕ-ИЛИ» 28-го и 31-го разрядов позволяет получить последовательность максимальной длины 231-1 или 2'147'483'647 тактов или 2.6 дня для максимальной скорости выдачи данных 9600 baud 15 . Сдвиговый регистр тактируется с частотой 1200 или 9600 сдвигов в секунду. Выходные данные собираются группами по 8 бит и обрамляются парой «START/STOP». Это формат асинхронной последовательной передачи, который используется в хорошо знакомом интерфейсе RS-232C. В соответствии со стандартом передача идёт в формате 8 бит, без чётности, один стоповый бит или 8N1 .
Рис. 11.7 Блок-схема генератора псевдослучайной последовательности с выходом через RS-232. 2-входовый мультиплексор ( MUX ) выбирает скорость асинхронной передачи. С этой частотой сдвигается регистр с обратными связями максимальной длины, который порождает псевдослучайную битовую последовательность. Далее она разбивается на байты, обрамляется стартовым и стоповым битами и сдвигается наружу в формате 8N1
В §14.7.8 объясняется, что реальные напряжения согласно стандарту RS-232C двуполярные и лежат в диапазоне ±5...±15 V . Указанные напряжения соответствуют двум логическим уровням, которые для большего удобства пользователя инвертированы, и логический ВЫСОКИЙ соответствует отрицательному уровню напряжения 16 . Существует много микросхем преобразователей уровня для RS-232C. Большая их часть имеет внутреннюю схему накачки заряда [* §9.6.3 ] и может работать от единственного положительного источника питания ( обычно 3.3—5V ). В схеме 11.8 используется MAX3232.
==772
11.3.2 Реализация устройства на стандартной логике
Вентили, счётчики, сдвиговые регистры - это всё то, что называется «стандартной логикой». Самым известным представителем является серия 74’, в которой перечисленные логические функции упакованы в стандартные корпуса DIP и во множество видов поверхностных ( SOIC, SSOP и др. ). На рис. 11.8 на элементах серии 74HC’ собран генератор псевдослучайных чисел. 74HC’ выбрана за доступность, разумное быстродействие, низкую потребляемую мощность и наличие тех самых DIP. На схеме указаны номера выводов корпуса, чтобы показать, что разработка успешно завершена. Несколько пояснений.
Рис. 11.8 Реализация устройства на стандартной логике ( семейство 74HC’ )
- Стандартная логика позволяет использовать свободные элементы «ИСКЛЮЧАЮЩЕЕ-ИЛИ» в качестве инверторов, что позволяет обойтись без дополнительных компонентов. Ещё одним примером является построение 2-входового мультиплексора для выбора частоты сдвига на незанятых элементах 17 .
- В схеме используются некоторые необычные микросхемы. Например, ‘HC4017 - полностью декодированный десятичный счётчик - используется для превращения 8 битов данных в 10-битовое слово для передачи по последовательному каналу. Обычно для таких задач используют отдельный счётчик и декодирующую логику. Ещё одна удобная микросхема ‘HC4040 - 12-разрядный счётчик пульсаций - используется в качестве делителя входной частоты вместо набора из 4-, 8-разрядных вариантов.
- Даже с учётом этих хитростей устройство состоит из 9 корпусов без учёта драйвера RS-232 - характерная особенность цифровых схем на стандартной логике. Все ИМС требуется соединить между собой проводниками, а после того, как монтаж закончен, любые модификации потребуют как минимум перепайки связей. Кроме того, схема состоит из шести видов микросхем, поэтому такая реализация потребует затрат на складское хранение широкой номенклатуры компонентов.
11.3.3 Реализация на программируемой логике
==773
Как отмечалось ранее, программируемая логика позволяет аккуратнее воплощать задачу «в железе». Данный пример - не исключение. Здесь программируемая логика гораздо точнее соответствует требованиям, чем стандартная. Девять корпусов заменяются одним, который, к тому же, позволяет исправлять ошибки и добавлять новые возможности.
Предложенный пример невелик и отлично помещается в cPLD, но был бы слишком мал для значительно более ёмких FPGA. На рис. 11.9 показана принципиальная схема с использованием cPLD на 64 макроячейки. Выбранная ИМС работает от 1.8 V , но допускает входные и выходные сигналы с уровнями от 1.5 до 3.3 V . Проект использует только 4 сигнальных вывода корпуса из 34 доступных, но зато почти все из 64 имеющихся триггеров. Цена ИМС около $2.
Рис. 11.9 программируемая логика позволяет сильно упростить схему. Соединения внутри cPLD задаётся программными инструментами: через графический схемный ввод или текстом на языке описания аппаратуры. Ниже показаны оба. В результате появляется карта соединений, которая загружается в постоянную память внутри PLD через четыре специальных вывода ( JTAG порт ).
11.3.3.A Программируемая логика - схемный ввод
Многие разработчики схем предпочитают графический «схемный ввод». Рис. 11.10 показывает, как выглядит генератор псевдослучайной битовой последовательности ( ПСП ) в окне графического редактора фирмы Xilinx.
Рис. 11.10 Графический ввод схемы для проекта, использующего ПО фирмы Xilinx. Схемные элементы могут быть как абстрактными логическими функциями, так и представителями стандартного семейства. Например, CB4CE - универсальный 4-разрядный двоичный счётчик со входом выбора кристалла, а, скажем, «163» ( 74xx163, на схеме отсутствует ) был бы стандартным 4-разрядным двоичным синхронным счётчиком с загрузкой, синхронным сбросом и установкой и Z-состоянием выходов. Кроме того, за графическими схемными элементами могут скрываться модули, представленные в текстовом формате на языке описания аппаратуры, например, VHDL
Символы можно выбирать как среди обычных вентилей ( OR2 - 2-входовая схема «ИЛИ» ), так и среди «асимметричных» ( AND2B1 - 2-входовая схема «И» с одним инвертированным входом ) или среди абстрактных цифровых функций ( CD4CE - 4-разрядный десятичный счётчик с сигналом выбора кристалла ). Можно нарисовать модуль представляющий какую-то часть схемы, например, соединяющий между собой несколько других модулей. Предложенный пример целиком помещается в одном модуле с двумя входами ( «SYSCLK» и «HIBAUD» ) и двумя выходами ( «ZERO» и «DOUT» ). Этот модуль может в дальнейшем использоваться в качестве логического блока в других схемах. Так же можно поступать и с текстовыми HDL файлами. Для них надо задать связи с графическим представлением, которое впоследствии можно использовать наравне со всеми прочими графическими элементами схемы. Можно, наоборот, получить текстовое представление через графический редактор: описать, например, машину состояний в виде диаграммы переходов в StateCAD фирмы Xilinx ( или в Altera Quartus ). На выходе программы будет текст на HDL ( Verilog, VHDL или ABEL ), который можно будет связать с графическим блоком.
Графический ввод позволяет промоделировать проект, чтобы убедиться, что всё работает, как задумано. Затем следует этап «размещения» и разводки , на котором создаётся список соединений для конкретной модели cPLD ( или FPGA ). На завершающем этапе конфигурация загружается в конкретную микросхему либо через программатор, либо внутрисхемно с помощью адаптера через специальные выводы корпуса, если ИМС уже запаяна на плату.
==774
Графический ввод позволяет получить для предложенного примера вполне читаемую схему. Разработчик 18 выбрал синхронную реализацию: все элементы устройства тактируются от одного источника - сигнала с внешнего генератора. Дело в том, что сдвиговые регистры и счётчики не будут корректно работать, если их тактировать сигналом, проходящим через логическую схему, например, с выхода счётчика пульсаций, хотя это совершенно нормальная практика для стандартной логики 19 .
Традиционной проблемой схемного ввода была завязка на аппаратуру конкретной фирмы, что затрудняло перенос проекта. Но в последнее время появились предложения ПО третьих фирм, позволяющего использовать и схемный ввод, и моделирование и, к тому же, совестимого с продукцией нескольких производителей FPGA. Один из таких вариантов - “NanoBoard” - серия наборов разработчика фирмы Altium, предназначенных для работы с их пакетом Designer. На данный момент поддерживаются FPGA фирм Altera ( серия Cyclone ), Lattice ( серия ECP2 ) и Xilinx ( серии Spartan и Virtex ). Если проект использует только библиотеки абстрактных логических элементов, то с переносом проблем не будет. Пример показан на рис. 11.11 . Опять уже знакомый генератор ПСП. Разработчик 20 предпочёл сгруппировать схему по функциональным модулям, чтобы увеличить читаемость. Если исключить входные и выходные буфера, которые специфичны для Xilinx, все прочие компоненты являются абстрактными логическими функциями и легко адаптируются под другую микросхему.
Рис. 11.11 Такой же проект, как и на рис. 11.10 , но созданный в среде Altium «Designer» для отладочной платы NanoBoard той же фирмы
==775
На более высоком уровне абстракции ( и стоимости ) можно взять набор инструментов для синтеза фирмы Synopsys - Synphony HLS . Разработка начинается в MATLAB и Simulink фирмы Math-Works. Среда позволяет сопрягать функциональные модули, выбираемые из библиотеки, подобно кубикам LEGO. В наборе есть цифровые фильтры, FFT и т.п. элементы. Проект передаётся ( через описание на HDL ) в Synphony, где происходит синтез под нужную FPGA или даже ASIC, а на выходе создаются в том числе: код функционального моделирования на языке Си, тестовые вектора и результаты временного моделирования. Такой путь гораздо проще, чем обычная разработка на языке высокого уровня, а удобство проверки текстового описания на HDL ( с учётом того, что функциональные блоки, которые он использует, гарантированно корректны ) позволяет получить результат гораздо менее склонный к ошибкам, чем столь же сложный проект, синтезированный обычными методами. Здесь, впрочем, стоит отметить, что такая реализация может быть не самой эффективной в терминах скорости, ресурсоёмкости и потребляемой мощности.
Преимущества схемного ввода
Разработчики, использующие графический ввод объясняют свой выбор следующим образом.
- Исходным предпочтением схемного ( естественного ) представления.
- Меньшими усилиями по изучению, лёгкости понимания и простотой объяснения другим людям.
- Предпочтением графической документации.
- Возможностью использования модулей на HDL там, где они действительно нужны.
- Использованием того же графического ввода в графических языках ( GPL ) LabVIEW, MATLAB® и Simulink®.
11.3.4 Программируемая логика - текстовый ввод
В качестве альтернативы графическому вводу служит текст на одном из языков описания аппаратуры. В данный момент имеются два фаворита - Verilog и VHDL, но постоянно предпринимаются попытки приспособить к этой задаче обычный Си.
Будет полезно посмотреть для начала, как проект будет выглядеть на ABEL, который стремится быть «ближе к железу». На ABEL надо определять выводы ( входные и выходные ) и узлы ( внутренние триггеры или вентили ), писать уравнения , которые задают взаимосвязь между сигналами, например, определяют входные данные для D-триггера и источник тактирования для него. Подобно схемному вводу можно промоделировать проект с помощью тестовых векторов , после чего запускается планировщик , который создаёт список соединений - «нетлист» ( его зовут jedec-файл ) для конкретной микросхемы. Наконец, надо загрузить полученную «прошивку» в кристалл с помощью внутрисхемного программатора.
11.3.4.A Программируемая логика - текстовый ввод ( ABEL )
На рис. 11.12 представлен исходный текст на ABEL, описывающий генератор псевдослучайной последовательности с использованием cPLD объёмом 64 макроячейки.
Рис. 11.12 Код на ABEL для генератора псевдослучайной последовательности
module PRBYTES title 'pseudo random byte generator - async serial Paul Horowitz, 10 Dec 07. rev 5' PRBYTES device 'XC2C64A'; // xilinx zeropower cPLD // Inputs osc pin; // 2.5476 MHz osc input ( 9600 baud x 256 ) rate pin; // LOW selects 1200 baud, HIGH selects 9600 baud // Outputs serout pin istype 'reg_D'; // serial data syncout pin istype 'com'; // RS-232 START pulse ( for testing ) // Nodes [sbc3..sbc0] node istype 'reg_D'; // serial bit counter, BCD ( 10 states, 0–9 ) [brd10..brd0] node istype 'reg_T'; // baud rate divider ( 256 or 2048 ) [sr30..sr0] node istype 'reg_D'; // 31-bit shift register for pseudorandom generator // Constants & Declarations high = 'b1; low = 'b0; baudclk = rate & brd7.q # !rate & brd10.q; // baud rate clock sbczero = !sbc3.1 & !sbc2.q & !sbc1.q & !sbc0.q; // serial bit counter is zero sbcnine = sbc3.1 & !sbc2.q & !sbc1.q & sbc0.q; // serial bit counter is nine Equations // baud rate divider: 11 bit binary ripple ctr, use bits 7 or 10 for baudrate [brd10..brd0].t = [1,1,1,1,1,1,1,1,1,1,1]; // all flops set to toggle brd0.clk = osc; // clock lsb from external osc [brd10..brd1].clk = [brd9..brd0].q // all higher bits clock from previous Q output // i.e., brd10.clk = brd9.q; // brd9.clk = brd8.q; etc // serial bit counter: synch BCD up-counter ( 4-bit, 10 states: 0–9 ) // useless 'sbcnine & low' term of top line was included for clarity only sbc0.d = !sbcnine & !sbc0.q # sbcnine & low; // LSB toggle, except reset after state 9 sbc1.d = !sbcnine & ( sbc0.q $ sbc1.q ); // toggle if lower bits set sbc2.d = !sbcnine & (( sbc1.q & sbc0.q ) $ sbc2.q ); sbc3.d = !sbcnine & (( sbc2.q & sbc1.q & sbc0.q ) $ sbc3.q ); // 31-bit xor-feedback shift register to generate pseudo-ran bits [sr30..sr0].clk = baudclk; // prbs shift register clocked at baud rate [sr30..sr1].d = [sr29..ar0].q; // compfct form for sr30.d = sr29.q; // sr29.d = sr29.q; etc sr0.d = !( sr30.q $ sr27.q ); // xor feedback to make prbs; // negation ensures startup from reset // append start and stop bits to generate RS-232 style async serial output bytes; serout.clk = baudclk; // do syncout serial output clocked at baud rate serout.d = ( !sbczero & sr30.q # sbczero & low ) # sbcnine & high; // stop bit ( high ) on nine? start bit ( low ) on zero, random on 1 through 8 // RS-232 drivers invert; stcond term in parenthesis, and 'high', a both unnecessary syncout = sbczero; // RS-232 start pulse end PRBYTES
Несколько пояснений ( сверху вниз по тексту ).
- Каждая строка заканчивается точкой с запятой, «//» начинает комментарий [* который завершается концом строки ] .
- Директива «istype» с последующими модификаторами «com», «reg_D» или «reg_T» определяет выходы и узлы как комбинационные или регистровые. Отсутствие модификатора обозначает вход.
- Набор однотипных сигналов ( «set» в терминах ABEL ) пишется как диапазон «[sr30..sr0]» ( 31-разрядный сдвиговый регистр ).
- Операции «НЕ», «И», «ИЛИ» и «ИСКЛЮЧАЮЩЕЕ-ИЛИ» обозначаются символами «!», «&», «#», «$».
- Переменные, не заданные как узлы или выходы ( как, например, «baudclk» ) являются простыми определениями , которые упрощают восприятие выражений ( подобно « [sr30..sr0].clk = baudclk » ). Здесь srn - имя разряда сдвигового регистра, а не зарезервированное слово языка.
- Стандартные выводы триггеров обозначаются в виде «расширения с точкой». Например, выражение «sr0.d = !(sr30.q $ sr27.q)» задаёт операцию «ИСКЛЮЧАЮЩЕЕ-ИЛИ» между выходами q разрядов 30 и 27 и подаёт результат на D-вход нулевого разряда ( это та самая цепь обратной связи, формирующая псевдослучайные биты ).
Стоит потратить некоторое время, чтобы разобраться в листинге и немного освоиться с описанием схемы в текстовом виде. Код подробно прокомментирован, чтобы облегчить эту задачу. Предлагаемая реализация - не самая эффективная, но вполне рабочая.
11.3.4.B Программируемая логика - текстовый ввод II ( Verilog )
Простые языки, вроде ABEL, удобны, когда речь идёт о небольших cPLD ( до 128 макроячеек ), но для сложных проектов и современных FPGA они совсем не подходят. ABEL и CUPL выросли из PALASM и имеют в своём составе конструкции вида «If-Then-Else», но на данный момент полностью вытеснены современными языками Verilog и VHDL. Оба имеют одинаковые возможности, но делят людей на два лагеря, превозносящих достоинства своего языка над конкурентом.
==776
==777
Рис. 11.13 Проект генератора псевдослучайной последовательности на Verilog, написанный с упором на поведение
// Pseudo random byte generator - async serial // Gu-Yeon and Curtis Mead; "behavioral" coding module RRBYTES( osc, rate, reset, serout ); // inputs // osc: 2.4576 MHz oscillator input ( 9600 baud x 256 ) // rate: 0 = 1200 baud, 1 = 9600 baud // reset: active high reset to clear out counters input osc, rate, reset; // outputs // serout: serial data output serout; // define registers reg serout; // a 'reg' is node that holds its value until overwritten reg [3:0] sbc; // RS-232 serial bit counter reg [10:0] brd; // baud rate divider reg [30:0] sr; // PRBS shift register // define wires. A 'wire' is a combinatorial circuit node wire baudclk, sbczero, sbcnine; // logic assign baudclk = rate & brd[7] | ~rate & brd[10]; // baud rate clk, div 256 or 2k assign sbczero = ~sbc[3] & ~sbc[2] & ~sbc[1] & ~sbc[0];// serial bit counter zero flag assign sbcnine = sbc[3] & ~sbc[2] & ~sbc[1] & sbc[0]; // serial bit counter nine flag // baud rate divider. 11 bit binary ctr. Use bits 7 or 10 for baudrate asways @(posedge osc) begin // logic clocked by osc if ( reset ) brd <= 0; else brd <= brd+1; end // serial bit counter. synch BCD up-count ( 4-bit, 10 states 0–9 ) // this is "begavioral"; see later program fragment for "structural" always @( posedge baudclk ) begin // logic clocked by baudclk if ( reset ) sbc <= 0; else if ( sbcnine ) sbc <= 4'b0000; else sbc <= sbc + 1; end // 31-bit xor-feedback shift register to generate pseudo-random bits always @( posedge baudclk ) begin if ( reset ) sr[0] <= 0; // prevent stuck state of all ones else begin sr[30:1] <= sr[29:0]; sr[0] <= ~( sr[30]^sr[27] ); // xnor makes all ones the stuck state end end // serial output stream cones from last SR bit, but overridden by "0" start, and "1" stop always @( posedge baudclk ) begin serout <= ( ~sbczero & sr[30] ) | sbcnine; end endmodule
Чтобы показать всю мощь текстового представления, генератор ПСП был закодирован и в Verilog, и в VHDL 21 . Выражения в этих языках могут составляться в терминах структуры ( какие символы подаются на вход ), а могут и в терминах поведения ( что должно произойти ). Примеры в большей степени соответствуют второму подходу, который предпочитают опытные разработчики. Но для одного участка кода будет показана структурная альтернатива. На рис. 11.13 показан проект на языке Verilog, соответствующий поведенческой модели, а на рис. 11.14 представлен структурный вариант 4-разрядного двоично-десятичного счётчика.
Рис. 11.14 4-разрядный двоично-десятичный счётчик, написанный на Verilog с упором на структуру
// alternative "structural coding of serial bit counter // synch BCD up-counter ( 4-bit, 10 stages: 0–9 ) always @( posedge baudclk ) begin sbc[0] <= ~sbcnine & ~sbc[0] & ~reset; sbc[1] <= ~sbcnine & ( sbc[0] ^ sbc[1] ) & ~reset; sbc[2] <= ~sbcnine & (( sbc[0] & sbc[1] ) ^ sbc[2] ) & ~reset; sbc[3] <= ~sbcnine & (( sbc[0] & sbc[1] & sbc[2] ) ^ sbc[3] ) & ~reset; end
Некоторые пояснения.
- Код на Verilog по своей структуре похож на ABEL.
- Ключевое слово « wire » объявляет внутренний узел, а « assign » определяет его.
- Подобно обычным языкам программирования Verilog и VHDL активно используют конструкции if, else if, else .
- Разработчики предпочитают конструкции, описывающие поведение, как более компактные и понятные как минимум в процессе проверки в ходе моделирования. Зато структурно ориентированный код позволяет получить более эффективную реализацию 22 .
Дополнительные детали. Проект использует два тактовых сигнала: быстрый ∼2.5 MHz и поделенный с большим коэффициентом до 1.2 или 9.6 kHz для последовательной передачи. Таким образом, получаем не полностью синхронную систему, хотя каждый счётчик сам по себе синхронный. Если проект предполагает реализацию в виде заказной ИС, всё отлично, но с типовыми cPLD или FPGA могут возникнуть трудности 23 . Самым правильным решением было бы тактировать оба счётчика через быструю глобальную линию, проходящую через все элементы схемы, разрешая срабатывание медленного счётчика на время одного такта из нужного их числа.
11.3.4.C Программируемая логика - текстовый ввод III ( VHDL )
Вторым популярным языком является VHDL. Он строже типизирован и восходит к языку программирования Ada ( Verilog ближе к Си ). VHDL чуть многословнее, чем Verilog. В данном варианте проекта используется чисто синхронный подход, т.е. частота 2.5 MHz используется и для задания скорости передачи и для подсчёта отдельных битов. В последнем случае тактовый импульс переключает на счётчик битов, только когда « nextbit » в разрешающем состоянии. Такая схема точно соответствует графическому варианту на рис. 11.10 и 11.11 . Код показан на рис. 11.15 .
Рис. 11.15 Полностью синхронный VHDL код генератора псевдослучайной последовательности
-- Pseudo random byte generator - async serial -- Curtis Mead, modeled after Gu-Yeon Wei's Verilog -- but implemented as a fully synchronous design -- COMMENTS begin with two dashes (--) library IEEE; use IEEE.STD_LOGIC_1164.ALL; entity PRBS is Port ( CLK : in STD_LOGIC; -- 2.4576 MHz oscillator RESET : in STD_LOGIC; -- Synchronous reset, active high BAUD_SELECT : in STD_LOGIC; -- 0 = 1200 baud, 1 = 9600 baud ZERO_pin : in STD_LOGIC; -- DATA_OUT_pin : in STD_LOGIC ); -- Serial data output end PRBS; architecture Behavioral of PRBS is signal sbc : STD_LOGIC_VECTOR( 3 downto 0 ); -- serial bit counter signal brd : STD_LOGIC_VECTOR( 10 downto 0 ); -- baud rate divider signal prbs_bits : STD_LOGIC_VECTOR( 30 downto 0 ); -- prbs shift register signal baudtemp : STD_LOGIC_VECTOR( 1 downto 0 ); -- brd temp register signal nextbit : STD_LOGIC; -- pseudo clock signal for serial bit counter signal sbcnine, sbczero : STD_LOGIC; begin -- PRBS with 31-bit shift register, bits 27 and 30 XNOR'ed into input process( CLK ) begin if CLK'event and CLK = '1' then if RESET = '1' then prbs_bits(0) <= '0'; elsif nextbit = '1' then prbs_bits( 30 downto 1 ) <= prbs_bits( 29 downto 0 ); prbs_bits(0) <= prbs_bits(27) xnor prbs_bits(30); end if; end if; end process; -- baud rate divider, 11 bit counter, synchronous reset -- use bit 7 for 9600 baud and bit 10 for 1200 baud process( CLK ) begin if CLK'event and CLK = '1' then if RESET = '1' then brd <= ( others => '0' ); else brd <= brd + 1; end if; end if; end process; -- shift register used to set nextbit for one clock only -- triggerid by baudrate divider bits -- for clocking nextbit from baud rate divider output 'baudtemp' process( CLK ) begin if CLK'event and CLK = '1' then if RESET = '1' then baudtemp <= "00"; else baudtemp(1) <= baudtemp(0); baudtemp(0) <= ( BAUD_SELECT and brd(7) ) or ( not BAUD_SELECT and brd(10) ); end if; end if; end process; nextbit <= baudtemp(0) and not baudtemp(1); -- nextbit high for one clock cycle -- serial bit counter 4-bit BCD up with synchronous clear process( CLK ) begin if CLK'event and CLK = '1' then if RESET = '1' then sbc <= ( others => '0' ); elsif nextbit = '1' then if sbcnine = '1' then sbc <= ( others => '0' ); else sbc <= sbc + 1; end if; end if; end if; end process; sbczero <= '1' when sbc = "0000" else '0'; -- serial bit counter zero flag sbcnine <= sbc(0) and sbc(3); -- serial bit counter nine flag -- output synchronous with clock signal CLK process( CLK ) begin if CLK'event and CLK = '1' then if RESET = '1' then DATA_OUT_pin <= '0'; ZERO_pin <= '0'; elsif nextbit = '1' then -- nextbit is an "enable" ( at the baudrate ) DATA_OUT_pin <= ( not sbczero and prbs_bits(30) ) or sbcnine ; ZERO_pin <= sbczero; end if; end if; end process; end Behavioral;
Преимущества текстового ввода
Разработчики, предпочитающие текстовый ввод, подкрепляют свой выбор следующими аргументами.
- Такой метод быстрее, если проект повторно использует уже написанный код.
- Текст лаконичнее ( а значит, проще понять, что всё правильно ) и самодокументируем ( текст же ).
- Процесс разработки формализован сильнее и постоянно подкрепляется этапами моделирования.
- Легко менять параметры ( число разрядов регистра, АЛУ и т.д. ), просто изменив индекс массива, что сильно контрастирует с перекомпоновкой графических элементов.
- Языки описания аппаратуры стандартизованы и используются повсеместно, чего нельзя сказать о графических библиотеках, привязанных к производителям кремния.
- Доступны хорошие бесплатные средства моделирования.
- HDL лучше приспособлены для высокоуровневого синтеза сложных проектов ( таких как микропроцессоры ) и отлаженных программных модулей ( IP cores ) с открытым исходным кодом, поставляемых в текстовой форме 24 .
- Текстовое представление лучше подходит для реализации в заказных ИС ( ASIC ), что бывает удобно, если проект предполагает выпуск большой партии сильно оптимизированной по скорости и потребляемой мощности, но стартует в FPGA варианте.
- Программистам текстовый ввод кажется более естественным.
11.3.5 Реализация на микроконтроллере
Микроконтроллеры ( µC ), которым отведена Часть 15 , - недорогие процессоры, предназначенные для использования в устройствах, не считающихся компьютерами . Их можно рассматривать как нечто промежуточное: уже не вполне компонент, но ещё не компьютер. Если сравнивать микроконтроллеры с микропроцессорами , стоящими в вычислительных машинах, то первые предназначены для самостоятельной работы, поэтому всегда имеют программную и оперативную память и некоторый набор «периферийных устройств»: средств коммуникации ( USB, firewire, Ethernet, UART, CAN, SPI, I2C ), АЦП, компараторы, линии цифрового ввода-вывода, таймеры и т.п. Многие имеют внутренний тактовый генератор, которому требуется только питание, причём точность достаточна для работы последовательной связи ( ±2% ). µC программируются ( и перепрограммируются ) внутрисхемно через последовательный интерфейс JTAG 25 или аналогичный. Модели последних разработок имеют в своём составе узел внутрисхемной отладки через тот же порт для программирования.
==778
==779
Микроконтроллеры недороги: стандартный ценовой диапазон начинается с десятков центов и доходит до десяти долларов. Выпускаются буквально тысячи вариантов десятков производителей. Очень популярны архитектуры PIC ( Microchip ), AVR ( Atmel ) и ARM ( лицензионное ядро ). Кроме того, по-прежнему в строю старая разработка Intel - ядро i8051. µC начального уровня обычно 8-разрядные с 1kB памяти программ, 128 байтами ОЗУ и частотой единицы мегагерц. На противоположном конце спектра - 32-разрядные модели с 512 kB памяти программ, 64 kB ОЗУ и богатым набором внутренней периферии 26 .
Микроконтроллеры на редкость универсальны. Их можно встретить почти в любом электронном устройстве: от тостера и зубной щётки до грузовиков и светофоров. Сделать генератор псевдослучайной последовательности совсем не сложно. «Схема» показана на рис. 11.16 . Достаточно подать питание и получить на выходе данные. Всё остальное делает программа, которая будет представлена в двух вариантах.
Рис. 11.16 Микроконтроллеры - альтернатива программируемой логике, особенно если скорость работы не критична. Данная конкретная микросхема ( выбранная среди тысяч ей подобных ) имеет внутри тактовый генератор и не требует никаких внешних компонентов, чтобы создавать поток данных на обычном логическом выводе
11.3.5.A Программа для микроконтроллера - ассемблер
Микроконтроллеры, подобно прочим процессорам, выполняют последовательность действий, обозначенных инструкциями, лежащими в программной памяти ( см. Часть 14 ). В случае µC речь идёт о постоянной памяти ( т.е. сохраняющей своё содержимое даже при отсутствии питания ). Набор инструкций специфичен для конкретного семейства процессоров, но обычно включает следующие группы команд: арифметические ( сложение ), логические ( сдвиг ), пересылки данных и перехода по адресу. Сами инструкции лежат в памяти в виде последовательности байт, которые процессор «перебирает» один за другим в ходе исполнения программы.
В процессе программирования не требуется работать с объектным кодом [* т.е. двоичными данными, в том виде, в котором они лежат в памяти программ ] - это и скучно и чревато ошибками. Программирование и отладка проводятся в понятном человеку формате: в виде текста на ассемблере или на языке высокого уровня ( обычно Си ли C++ ). Такой текст нужно ассемблировать или компилировать с помощью специальных программ, чтобы получить двоичный объектный код, который затем загружается в программную память контроллера. Есть отличные инструменты позволяющие понять, что код работает правильно. Это симулятор , он позволяет пройтись по программе шаг за шагом, и отладчик , который показывает, что именно происходит в микроконтроллере, когда тот исполняет код уже прямо в схеме. Термин «интегрированная среде разработки» ( “IDE” ) обозначает набор программ ( компилятор, ассемблер, загрузчик, отладчик ), которые нужны для создания программ для целевого микроконтроллера.
На рис. 11.17 приводится ассемблерный код генератора ПСП, соответствующий схеме 11.16 .
Рис. 11.17 Генератор псевдослучайной последовательности на ассемблере
;; program to send rseudo-random bytes from strial UART rev of 12/14/07 org 00h; starting address at power up or reset mov IE, #00h; disable interrupts mov SP, #90h; init stack pointer, used for subroutine mov PCON, #00h; mov TMOD, #20h; timer_1: 8 bit, auto reload mov TCON, #40h; timer_0 off, timer_1 on mov SCON, #40h; 8 bit UART, tx only. set by timer_1 mov TH1, #0FDh; 9600 baud ( reload value = 253 decimal ) clr A; clr TI; jb P1.0, makebyte; logic HIGH input on P1.0 pin = 9600 baud mov TH1, #0E8h; LOW: 1200 baud ( reloal value = 232 decimal makebyte: mov R3, #8; setup loop counter - 8 shifts make a byte makebit: ;create feedback bit as XNOR of bits 27 and 30 (30..0) mov C, ACC.4; that is, ACC.4 and ACC.1 mov R2, #0; mov R2.1, C; stick ACC.4 into R2.1, to XNOR with masked ACC anl A, #2; mask ACC, preserving ACC.1 only clr C; cjne A, R2, loadreg; XNOR=0, carry already cleared setb C; XNOR=1, set carry loadreg: mov R0, #80h; 80–83h will hold MSByte–LSByte of 32-bit SR shift32: mov A, @R0; R0 points to one of 4 bytes at 80h..83h rrc A; shift right through carry mov @R0, A; stash it inc R0; cjne R0, #84h, shift32; check for last byte of 4 djnz R3, makebit; do it 8 times acall sendbyte; send finished byte via serial UART sjmp makebyte; and start next byte ; code for sending one byte sendbyte: jnb TI, sendbyte; wait for last tx done mov SBUF, A; load transmit buffer ret; end
==780
==781
==782
Несколько пояснений ( хотя это и не учебник программирования ).
- Все микроконтроллеры имеют набор «регистров специального назначения». Заполняя их определёнными значениями, можно настроить режимы работы таймеров, прерываний, установить указатель стека и т.п. Именно этим заняты семь первых инструкций « mov ». Разобраться в нужных режимах таймеров и скоростей передачи не слишком легко, поэтому удобнее всего просто скопировать нужный код из заведомо работающей программы. Ничего общего в такого рода действиях для контроллеров разных семейств нет, и с каждым придётся разбираться заново.
- Строчки « org 00h » и « end » говорят ассемблеру, по какому адресу в памяти размещать первую инструкцию, и где заканчивается текст программы. Это не исполняемые инструкции микроконтроллера, но директивы управления самой программой-ассемблером. Иногда их называют «псевдоинструкции». [* Они идентичны по задачам и действию «прагмам» на языке Си, просто немного иначе оформляются ] .
- Остальной текст состоит из обычных операций - арифметических, логических, очистки, сравнения, копирования, организации циклов и вызовов подпрограмм. Вряд ли вам захочется заниматься этим всю жизнь, но посмотреть, как оно выглядит, полезно.
11.3.5.B Программа для микроконтроллера - язык Си
Ассемблер - довольно медитативная штука, к тому же, позволяет делать тривиальнейшие ошибки. Даже если всё сделано правильно, вносить изменения в программу будет затруднительно. Большие программы отнимают много сил. Код требуется переписывать полностью, если хочется использовать другое семейство микроконтроллеров. И хуже всего то, что уже через пару недель трудно вспомнить, что же тут, собственно, написано.
Все эти соображения подвигают людей к использованию языков высокого уровня, например, Си или C++ 27 . На них проще писать, текст понятнее, программу проще переносить на другое семейство микроконтроллеров ( но какие-то изменения, отражающие разницу архитектур, понадобятся обязательно ). На рис. 11.18 представлен текст генератора псевдослучайной последовательности на языке Си.
Рис. 11.18 Генератор псевдослучайной последовательности на языке Си
#include <avr/io.h> #define F_CPU 20000000 // 20 MHz #define BAUD_RATE 9600 // or 115200 void USART_Init( void ) { UBRR0 = R_CPU/BAUD_RATE/8 - 1; // Set baud rate UCSR0A = ( 1<<U2X0 ); // Change baud divisor from 16 to 8 UCSR0B = ( 1<<RXEN0 ) | ( 1<<TXEN0 ); // enable Rx & Tx UCSR0C = ( 1<<UCSZ01 ) | ( 1<<UCSZ00 );// 8N1 } void putch( unsigned char ch ) { while ( !( UCSR0A & ( 1<<UDREo )) ); UDR0 = ch; } int main ( void ) { unsigned char out; undigned char d=0xff, c=0xff, b=0xff, a=0xff; USART_Init(); while(1) { out = ( ( d<<1 ) | ( c>>7 ) ^ c; // 31 bit, tap 24 d = c; c = b; a = out; putch ( out ); } }
Автор программы 28 отметил, что для генераторов псевдослучайных последовательностей можно использовать эффективные алгоритмы, дающие на выходе полный байт данных, а не громоздкий побитовый вариант, как здесь. Сдвиговый регистр содержит всю нужную информацию, позволяющую рассчитать новое состояние для всех разрядов до первого отвода обратной связи ( здесь это 28-ой бит [* bit_27, потому что счёт идёт с 0 ] ). Если учесть 8-разрядную организацию микроконтроллера и объём данных, которые UART принимает за одно обращение ( 8 бит ), правильнее было бы вычислять этот байт сразу с использованием «ИСКЛЮЧАЮЩЕГО-ИЛИ» над 8-разрядными данными без учёта переносов. Такая программа работает чертовски быстро.
==782
11 Или пресловутая обезьяна за пишущей машинкой ( monkey-at-a-typewriter ). <-
12 Самые популярные - Verilog и VHDL. <-
13 Иногда называется сдвиговым регистром с линейными обратными связями ( LFSR ), см. §8.12.4.A [* и §13.14.2 ] . <-
14 Следует отметить, что есть более совершенные методы получения псевдослучайных последовательностей вычислительными методами. Данный способ выбран исключительно из-за простоты реализации. <-
15 Читателям, озабоченным тем фактом, что псевдослучайная последовательность повторяется , могут попробовать чуть более длинные сдвиговые регистры. Скажем, для 71 бита ( отвод от 65-го разряда ) время одного цикла составляет примерно 8 миллиардов лет ( примерно половина возраста вселенной ). Настоящие пуристы выберут последовательность в 167 бит ( отвод от 161-го разряда ). Цикл длится \(10^{38}\) лет ( примерно в \(10^{28}\) раз больше возраста вселенной ). [* См. табл. 13.14 ( стр. 976 ) ] . <-
16 Их ещё зовут MARK и SPACE соответственно. <-
17 Следует учесть, что логические вентили доступны и более мелкими порциями в форме малоногих ИМС с 1...3 вентилями. Такая разновидность зовётся “TinyLogic™” ( Fairchild ), “PicoGate™” ( NXP ), “MiniGate™” ( ON Semiconductor ), “Little Logic™” ( TI ), Single Gate ( ST ) и LMOS™ ( Toshiba ). В книге все они зовутся «mini-logic», потому что это словосочетание не приватизировано ни одним крупным игроком. Такие кристаллы очень удобны, когда требуется минимальная обвязка. <-
18 Авторы благодарны Джиму МакАртуру (Jim MacArthur) за отзывчивость и подготовку обоих проектов. <-
19 К сожалению, задержки сигналов, проходящих через матрицу межсоединений, вызывают неприемлемый сдвиг фронта ( §10.8.2.C ). [* Ёмкость матрицы межсоединений зависит от общего числа связей в ИМС. Больше связей - выше ёмкость - сильнее задержка ] . Только «глобальные сигналы» обеспечивают заявленные в справочных данных параметры. Этот факт отмечен в руководстве пользователя. <-
20 Это всё тот же Кёртис Мид (Curtis Mead), которому авторы очень обязаны. <-
21 Авторы в долгу перед коллегами ГуЁном Вей (GuYeon Wei) и Кёртисом Мидом (Curtis Mead), закодировавшими оба примера. <-
22 Примером может служить 32-разрядный счётчик. Описание с упором на поведение «count=count+1» может скомпилироваться в 32-разрядный регистр в паре с полным сумматором, прибавляющим константу 0x00000001 . <-
23 Некоторые FPGA позволяют заводить на тактовые входы логические сигналы ( Virtex-5 ), а некоторые - нет ( Spartan-3 ). Для второго варианта придётся заводить тактовый сигнал через внешний вывод корпуса [* т.е. выводить логический сигнал наружу и подключать его к свободному выводу глобального тактирования ] . <-
24 Но программные блоки ( IP ), требующие лицензирования будут зашифрованы. <-
25 4-проводная шина, которая допускает последовательное включение абонентов и обеспечивает загрузку, проверку и выключение их внутренних регистров в реальном времени, см. §14.7.4 . <-
26 Вот, например, LPC2458 фирмы NXP ( рис. 10.86 ): ARM7, память 512kB/64kB, скорость 72 MHz, 10/100 Ethernet, USB 2.0, 10-разрядные АЦП и ЦАП, 2 канала ШИМ, 4 UART, 2 CAN, SPI, 2 SSP, 3 I2C, I2S, 136 линий ввода-вывода и контроллер внешней памяти. Стоит всего $10! Если хочется чего-нибудь погорячее, гляньте на ARM9 <-
27 Возможно, с небольшими вставками на ассемблере там, где важна скорость, например в обработчике прерываний ( см. Часть 14 [* §14.3.7 ] ). <-
28 Джейсон Галиччо (Jason Gallicchio), который написал код и активно участвовал в дискуссии по микроконтроллерам. <-