1i7 (1i7) wrote,
1i7
1i7

Categories:

Лабораторная работа 3: делаем память (защелки и триггеры) (2)

Продолжение лабороторной работы, начало в предыдущей записи <<



Упражнение 3: D защелка (D latch) на ПЛИС+Verilog

Переходим к более полезной с практической точки зрения реализации защелки - D защелка (D latch). Логическая схема этой защелки выглядит следующим образом:






Упрощенное обозначение D защелки на схемах


Защелка состоит из 2х операторов AND, одного оператора NOT и одной NOR-RS-защелки. Управляющих входа в схему  опять два, но их роль уже другая. Вход D задает значение, которое может быть сохранено в схеме, вход CLK открывает защелку на прием значения с D или закрывает ее так, чтобы она сохранила последнее значение и вход D на него больше не влиял.

Чтобы понять, как это работает, можно опять обратиться к таблице истинности этой схемы:



1. CLK=1, D=0: верхний AND на входе получает 1 и 1 => R получает 1; нижний AND получает 1 и 0 => S пулучает 0. Получаем ситуацию R=1, S=0 => Q=0, ~Q=1 (см объяснения из упражнения 1 с поправкой на таблицу истинности NOR для упражнения 2) => произошла запись в RS защелку значения 0 (будем считать, что текущее значение защелки это значение выхода Q, ~Q - просто инверсия). За текущее значение D защелки принимаем текущее значени RS защелки.

2. CLK=1, D=1: зеркально предыдущему случаю - в D защелку записали значение 1.

3. CLK=0, D=0/1: Т.к. значение CLK=0, очевидно оба значения выходов-входов R и S равны 0 (действие операторов AND), т.е. RS защелка находится в состоянии запоминания последнего установленного в нее значения, новые значения из D просто никак не влияют на схему, т.е. не принимаются.

Итого получаем:
CLK=1: защелка находится в прозрачном (transparent) состоянии - данные идут от D к Q.
CLK=0: защелка находится в непрозрачном (opaque) состоянии - данные от D к Q не идут, защелка сохраняет установленное значение.

Как видно, преимуществом D защелки заключается как минимум уже в том, что для изменения текущего сохраненного значения используется всего один входной сигнал. Второй управляющий сигнал используется для перевода схемы из состояния "открыто для получения нового значения" (прозначна) в состояние "закрыто - последнее значение сохранено" (непрозрачна) и обратно. При этом любые комбинации состояний входных сигналов защелки являются корректными.

Для лучшего визуального понимания описанного выше принципа работы можно посмотреть такой мультик - подъемная дверь (CLK) пускает или не пускает космонавтов снаружи (D) в капсулу (Q):



Попробуем реализовать эту схему на ПЛИС+Verilog и убедиться, что все работает именно так, как описано на расшифровке схемы.

flip_flops.v и flip_flops_top.v
/**
 * D latch
 */

module d_latch(
    input clk, input d,
    output q, output not_q
    );

    wire r, s;

    assign r = clk & ~d;
    assign s = clk & d;

    rs_latch rs(.r(r), .s(s), .q(q), .not_q(not_q));
endmodule

// D latch test top module
module d_latch_top(
    input [0:0] sw,
    input [72:72] pio,
    output [0:1] ld
    );

    d_latch d (.clk(sw[0]), .d(pio[72]),
            .q(ld[0]), .not_q(ld[1]));
endmodule

модуль rs_latch из предыдущего упражнения.

basys2_d_latch.ucf
# D latch
NET "sw<0>" LOC = "p11";
NET "PIO<72>" LOC = "B2";
NET "ld<1>" LOC = "m11" ;
NET "ld<0>" LOC = "m5" ;

На сигнал D назначили свободный провод PIO, на CLK - рычажок SW (рычажок наверху - CLK=HIGH=1, рычажок внизу - CLK=LOW=0), Q и ~Q - две лампочки LED.

Т.е. когда рычажок находится в верхнем положении (CLK=1) - защелка прозрачна и принимает те значения, которые мы подаем ей через свободный провод D (лампочки моргают). Когда рычажок находится в нижнем положении (CLK=0) - защелка непрозрачна - она сохраняет то значение, которое было подано на D в момент перевода рычажка в нижнее положение, подача новых значений на D в такой ситуации роли не играет (лампочки не моргают).















Упражнение 4: D триггер (D flip-flop) на ПЛИС+Verilog

Еще немного усложняем предыдущую схему в сторону большей практической полезности - добавляем буферную зону.





Упрощенное обозначение D триггера на схемах


Особым образом совмещаем на схеме 2 D защелки - получаем D триггер (D flip-flop). Левую D защелку назовем хозяин (master), правую - раб (slave).

Сигнал CLK к обеим защелкам подключен один и тот же, только в одну из защелок он поступает в инвертированном состоянии, т.е. в каждый момент времени одна защелка является прозрачной, а вторая непрозрачной и наоборот. Входной сигнал D, несущий внешнее устанавлимое значение, входит в левую D защелку master; выход R левой защелки master подключен к входу D правой защелки slave. За текущее значение D триггера принимаем значение правой защелки slave.

Таким образом, если вникнуть в эту схему, то можно понять, что входной сигнал D может передать свое значение в определяющую значение D триггера защелку slave только пройдя через буферную защелку master. Для этого нужно:

1. Сначала защелку master сделать прозрачной (CLK=0) так, что она начнет принимать входящий сигнал D - защелка slave при этом будет непрозрачной, поэтому дальше защелки master в этот момент сигнал D не проберется.

2. Когда нужное значение в защелку master установлено, делаем прозрачной уже защелку slave (CLK=1) - значение переходит из защелки master в защелку slave - значение триггера установлено. При этом важно, что в этот же момент сама защелка master переходит из прозрачного в непрозрачное состояние, поэтому процессу передачи значения master->slave внешний сигнал D помешать не может.

Таким образом получается, что запись в D триггер происходит только на ребре (edge) сигнала CLK именно в тот момент, когда он переходит из состояния LOW (0) в HIGH (1) - после этого внешний сигнал D никак повлиять на значение триггера не может.



Визуально механизм можно представить в виде переходной камеры на космическом корабле или подводной лодке:



Реализация на ПЛИС+Verilog:

flip_flops.v и flip_flops_top.v
/**
 * D flip-flop
 */

module d_flip_flop(
    input clk, input d,
    output q, output not_q
    );

    wire n1;

    // master
    d_latch l1 (.clk(~clk), .d(d), .q(n1));

    // slave
    d_latch l2 (.clk(clk), .d(n1), .q(q), .not_q(not_q));
endmodule

// D flip-flop test top module
module d_flip_flop_top(
    input [0:0] sw,
    input [72:72] pio,
    output [0:1] ld
    );

    d_flip_flop d (.clk(sw[0]), .d(pio[72]),
            .q(ld[0]), .not_q(ld[1]));
endmodule

basys2_d_flip_flop.ucf
# D flip-flop
NET "sw<0>" LOC = "p11";
NET "PIO<72>" LOC = "B2";
NET "ld<1>" LOC = "m11" ;
NET "ld<0>" LOC = "m5" ;

Устройства ввода-вывода назначаем абсолютно аналогично D защелке. D назначили свободный провод PIO, на CLK - рычажок SW (рычажок наверху - CLK=HIGH=1, рычажок внизу - CLK=LOW=0), Q и ~Q - две лампочки LED.

Рычажок внизу - CLK=0 - защелка master прозрачна - промежуточная капсула открыта и готова принимать внешние значения, защелка slave непрозрачна - получаемы в защелку master значения значение триггера не меняют (лампочка сохраняет состояние вне зависимости от того, куда вставлен провод D).

Рычажок вверху - CLK=1 - защелка slave прозрачна, защелка master непрозрачна - последнее значение из master переходит в slave и более не меняется (лампочка меняет состояние на значение сигнала D в момент перевода рычага в верхнее положение и более не меняется вне зависимости от того, куда вставлен провод D после этого).














Такой механизм позволяет например сделать процесс подачи нового значения в несколько триггеров одновременно более предсказуемым. Допустим, у нас есть несколько однобитных триггеров и мы хотим в них записать какое-то двоичное значение. Конкретный момент появления текущих значений на входных сигналах каждого триггера в общем случае непредсказуем и в случае набора открытых D защелок они могли бы случайным образом асинхронно менять (по сути повредить) их внутреннюю память до того момента, как защелка не захлопнулась. При добавлении буферной зоны из дополнительной D защелки master, непредсказуемость подобного поведения обрезается - если все триггеры подключены к одному и тому же управляющему сигналу (который закрывает и открывает триггер), все значения из буферных защелок отправятся во внутренние значимые защелки одновременно. Также на механизме D триггера основан принцип работы одной из наиболее важной в языке Verilog конструкции 'always @'.






Упражнение 5: 0.5 байта (4 бита) из 4х D триггеров на ПЛИС+Verilog

Все элементарно - подключаем 4 модуля D flip-flop к 4м внешним входам и одному тактовому сигналу CLK (в нашем случае - рычажку на плате) - получаем 4хбитный регистр, запись в который происходит при движении рычажка вниз-вверх.



Для имплементации на Verilog на этот раз достаточно добавить только новый топ-модуль - все остальное уже есть.

flip_flops_top.v
// 4-bit register with 4 D flip-flops test top module
module d_4bit_register_top(
    input [0:0] sw,
    input [72:75] pio,
    output [0:3] ld
    );

    d_flip_flop d1 (.clk(sw[0]), .d(pio[72]), .q(ld[3]));
    d_flip_flop d2 (.clk(sw[0]), .d(pio[73]), .q(ld[2]));
    d_flip_flop d3 (.clk(sw[0]), .d(pio[74]), .q(ld[1]));
    d_flip_flop d4 (.clk(sw[0]), .d(pio[75]), .q(ld[0]));
endmodule

basys2_d_4bit_regirster.ucf
# 4-bit register with 4 D flip-flops
NET "sw<0>" LOC = "p11";

NET "PIO<72>" LOC = "B2";
NET "PIO<73>" LOC = "A3";
NET "PIO<74>" LOC = "J3";
NET "PIO<75>" LOC = "B5";

NET "ld<3>" LOC = "p6" ;
NET "ld<2>" LOC = "p7" ;
NET "ld<1>" LOC = "m11" ;
NET "ld<0>" LOC = "m5" ;

Ввод-вывод - 4 провода по одному на каждый триггер (т.е. на каждый бит регистра) и 4 лампочки на этот раз по одной на каждый триггер. Рычажок SW - общий CLK. Ввод данных - устанавливаем внешний входы на нужные значения и двигаем рычаг вниз-вверх (в точности как для одного D триггера) - 4 бита запасываются в регистр одновременно, о чем сразу сообщают лампочки.













Заключение.

Очевидно, что для реальной работы с памятью внутри ПЛИС использование таких самописных модулей конечно не требуется - для этого там уже есть встроенные более оптимальные и удобные инструменты, которые называются регистры - например, чтобы объявить переменную Verilog, которая будет уметь запоминать любое значение, достаточно объявить ее с ключевым словом "reg". Но после выполнения данной лабоработорной работы становится понятно, какие механизмы могут лежать в основе этих абстракций.

Кроме того, данная лаба закрепляет навыки работы с макетной платой, которые были получены на первой лабораторной работе и навыки работы с модулями Verilog и ПЛИС, которые были получены на второй.


Код лабы на github, прообраз космонавтов, подсветка синтаксиса
Tags: verilog, плис, цифровая электроника для программистов
Subscribe

  • Post a new comment

    Error

    default userpic

    Your IP address will be recorded 

    When you submit the form an invisible reCAPTCHA check will be performed.
    You must follow the Privacy Policy and Google Terms of use.
  • 3 comments