Шапка

11.3 Пример: генератор псевдослучайной последовательности

Самый быстрый способ изучения того, как какая-то идея может выглядеть при разных способах реализации - посмотреть примеры. Предлагаемый к реализации проект - «генератор бреда» 11 - схема, которая выдаёт наружу псевдослучайные данные в виде последовательных 8-разрядных слов через стандартный асинхронный порт RS-232. Сначала будет разобрана конструкция , затем показана принципиальная схема, собранная

  1. на жёсткой логике ,
  2. на программируемых логических схемах с использованием двух популярных методов задания проектного файла: схемного ввода и текста на языке описания аппаратуры 12 ,
  3. наконец, посмотрим, как та же задача решается на микроконтроллере .

Микроконтроллер - недорогой ( и незаменимый ) однокристальный компьютер, прямо предназначенный для «встраивания» в электронные приборы и имеющем в своём распоряжении память и периферийные устройства. Сами микроконтроллеры рассматриваются в Части 15 , но трудно удержаться от показа их возможностей, просто потому что это достаточно привлекательная альтернатива.

Часть завершается разделом с советами, какие компоненты использовать, как работать с программными инструментами с аргументацией за и против.

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.

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 Реализация на программируемой логике

Как отмечалось ранее, программируемая логика позволяет аккуратнее воплощать задачу «в железе». Данный пример - не исключение. Здесь программируемая логика гораздо точнее соответствует требованиям, чем стандартная. Девять корпусов заменяются одним, который, к тому же, позволяет исправлять ошибки и добавлять новые возможности.

Предложенный пример невелик и отлично помещается в 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 ). На завершающем этапе конфигурация загружается в конкретную микросхему либо через программатор, либо внутрисхемно с помощью адаптера через специальные выводы корпуса, если ИМС уже запаяна на плату.

Графический ввод позволяет получить для предложенного примера вполне читаемую схему. Разработчик 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 той же фирмы

На более высоком уровне абстракции ( и стоимости ) можно взять набор инструментов для синтеза фирмы Synopsys - Synphony HLS . Разработка начинается в MATLAB и Simulink фирмы Math-Works. Среда позволяет сопрягать функциональные модули, выбираемые из библиотеки, подобно кубикам LEGO. В наборе есть цифровые фильтры, FFT и т.п. элементы. Проект передаётся ( через описание на HDL ) в Synphony, где происходит синтез под нужную FPGA или даже ASIC, а на выходе создаются в том числе: код функционального моделирования на языке Си, тестовые вектора и результаты временного моделирования. Такой путь гораздо проще, чем обычная разработка на языке высокого уровня, а удобство проверки текстового описания на HDL ( с учётом того, что функциональные блоки, которые он использует, гарантированно корректны ) позволяет получить результат гораздо менее склонный к ошибкам, чем столь же сложный проект, синтезированный обычными методами. Здесь, впрочем, стоит отметить, что такая реализация может быть не самой эффективной в терминах скорости, ресурсоёмкости и потребляемой мощности.

Преимущества схемного ввода

Разработчики, использующие графический ввод объясняют свой выбор следующим образом.

  1. Исходным предпочтением схемного ( естественного ) представления.
  2. Меньшими усилиями по изучению, лёгкости понимания и простотой объяснения другим людям.
  3. Предпочтением графической документации.
  4. Возможностью использования модулей на HDL там, где они действительно нужны.
  5. Использованием того же графического ввода в графических языках ( 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

Несколько пояснений ( сверху вниз по тексту ).

  1. Каждая строка заканчивается точкой с запятой, «//» начинает комментарий [* который завершается концом строки ] .
  2. Директива «istype» с последующими модификаторами «com», «reg_D» или «reg_T» определяет выходы и узлы как комбинационные или регистровые. Отсутствие модификатора обозначает вход.
  3. Набор однотипных сигналов ( «set» в терминах ABEL ) пишется как диапазон «[sr30..sr0]» ( 31-разрядный сдвиговый регистр ).
  4. Операции «НЕ», «И», «ИЛИ» и «ИСКЛЮЧАЮЩЕЕ-ИЛИ» обозначаются символами «!», «&», «#», «$».
  5. Переменные, не заданные как узлы или выходы ( как, например, «baudclk» ) являются простыми определениями , которые упрощают восприятие выражений ( подобно « [sr30..sr0].clk = baudclk » ). Здесь srn - имя разряда сдвигового регистра, а не зарезервированное слово языка.
  6. Стандартные выводы триггеров обозначаются в виде «расширения с точкой». Например, выражение «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. Оба имеют одинаковые возможности, но делят людей на два лагеря, превозносящих достоинства своего языка над конкурентом.

Рис. 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

Некоторые пояснения.

  1. Код на Verilog по своей структуре похож на ABEL.
  2. Ключевое слово « wire » объявляет внутренний узел, а « assign » определяет его.
  3. Подобно обычным языкам программирования Verilog и VHDL активно используют конструкции if, else if, else .
  4. Разработчики предпочитают конструкции, описывающие поведение, как более компактные и понятные как минимум в процессе проверки в ходе моделирования. Зато структурно ориентированный код позволяет получить более эффективную реализацию 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;

Преимущества текстового ввода

Разработчики, предпочитающие текстовый ввод, подкрепляют свой выбор следующими аргументами.

  1. Такой метод быстрее, если проект повторно использует уже написанный код.
  2. Текст лаконичнее ( а значит, проще понять, что всё правильно ) и самодокументируем ( текст же ).
  3. Процесс разработки формализован сильнее и постоянно подкрепляется этапами моделирования.
  4. Легко менять параметры ( число разрядов регистра, АЛУ и т.д. ), просто изменив индекс массива, что сильно контрастирует с перекомпоновкой графических элементов.
  5. Языки описания аппаратуры стандартизованы и используются повсеместно, чего нельзя сказать о графических библиотеках, привязанных к производителям кремния.
  6. Доступны хорошие бесплатные средства моделирования.
  7. HDL лучше приспособлены для высокоуровневого синтеза сложных проектов ( таких как микропроцессоры ) и отлаженных программных модулей ( IP cores ) с открытым исходным кодом, поставляемых в текстовой форме 24 .
  8. Текстовое представление лучше подходит для реализации в заказных ИС ( ASIC ), что бывает удобно, если проект предполагает выпуск большой партии сильно оптимизированной по скорости и потребляемой мощности, но стартует в FPGA варианте.
  9. Программистам текстовый ввод кажется более естественным.

11.3.5 Реализация на микроконтроллере

Микроконтроллеры ( µC ), которым отведена Часть 15 , - недорогие процессоры, предназначенные для использования в устройствах, не считающихся компьютерами . Их можно рассматривать как нечто промежуточное: уже не вполне компонент, но ещё не компьютер. Если сравнивать микроконтроллеры с микропроцессорами , стоящими в вычислительных машинах, то первые предназначены для самостоятельной работы, поэтому всегда имеют программную и оперативную память и некоторый набор «периферийных устройств»: средств коммуникации ( USB, firewire, Ethernet, UART, CAN, SPI, I2C ), АЦП, компараторы, линии цифрового ввода-вывода, таймеры и т.п. Многие имеют внутренний тактовый генератор, которому требуется только питание, причём точность достаточна для работы последовательной связи ( ±2% ). µC программируются ( и перепрограммируются ) внутрисхемно через последовательный интерфейс JTAG 25 или аналогичный. Модели последних разработок имеют в своём составе узел внутрисхемной отладки через тот же порт для программирования.

Микроконтроллеры недороги: стандартный ценовой диапазон начинается с десятков центов и доходит до десяти долларов. Выпускаются буквально тысячи вариантов десятков производителей. Очень популярны архитектуры 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

Несколько пояснений ( хотя это и не учебник программирования ).

  1. Все микроконтроллеры имеют набор «регистров специального назначения». Заполняя их определёнными значениями, можно настроить режимы работы таймеров, прерываний, установить указатель стека и т.п. Именно этим заняты семь первых инструкций « mov ». Разобраться в нужных режимах таймеров и скоростей передачи не слишком легко, поэтому удобнее всего просто скопировать нужный код из заведомо работающей программы. Ничего общего в такого рода действиях для контроллеров разных семейств нет, и с каждым придётся разбираться заново.
  2. Строчки « org 00h » и « end » говорят ассемблеру, по какому адресу в памяти размещать первую инструкцию, и где заканчивается текст программы. Это не исполняемые инструкции микроконтроллера, но директивы управления самой программой-ассемблером. Иногда их называют «псевдоинструкции». [* Они идентичны по задачам и действию «прагмам» на языке Си, просто немного иначе оформляются ] .
  3. Остальной текст состоит из обычных операций - арифметических, логических, очистки, сравнения, копирования, организации циклов и вызовов подпрограмм. Вряд ли вам захочется заниматься этим всю жизнь, но посмотреть, как оно выглядит, полезно.

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-разрядными данными без учёта переносов. Такая программа работает чертовски быстро.

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), который написал код и активно участвовал в дискуссии по микроконтроллерам. <-

Previous part:

Next part: