Case Verilog

Содержание

Case — это оператор выбора, который сравнивает значение переменной или выражения со случаем перечисленным в нем для выполнения блока кода при удачном совпадении или в ином случае по умолчанию, если был прописан соответствующий оператор. Оператор начинается с ключевого слова case и заканчивается endcase. Помимо определенных случаев можно указать исполнение по умолчанию через ключевое слово default, если совпадений не было найдено.

Принцип работы оператора case изложен следующих пунктах:

1) Вычисляется значение выражения или переменной.
2) Найденное значение в порядке возрастание сравнивается с константами выражениями из заданного списка.
3) Если находится совпадение с одним из случаев, то исполняется блок кода, связанный с этим ним.
4) Когда совпадений не было обнаружено, исполняется оператор по умолчанию, следующие за ключевым словом default.

Объявление случаев с одинаковыми значениями или не моделируемыми переменными является ошибкой. Если битовая ширина сравниваемых значения не равна, то значение меньшей длины дополняется нулями в старших битах до одинаковой длины.

Синтаксис

Синтаксис объявления оператора выбора case c блоком выполнения по умолчанию default.

case (/* переменная или выражение */) (/* случай 1 */): begin // объявление кода end (/* случай 2 */): begin // объявление кода end (/* случай 3 */): begin // объявление кода end ... (/* случай n */): begin // объявление кода end default: begin // объявление кода end endcase
Синтаксис 1 — Оператор case Verilog.

Примеры

Выбор оконечного устройства контроллером c сase

В примере реализован входной контроллер источника, в котором помощью оператора case выбираем получателя данных через интерфейс SPI. В потоке данных отлавливаем первый бит, который является адресом получателя. После получение всех слов потока и сохранение в памяти(см. 4.9.3 Память), производим сравнивание этого адреса через case. При совпадении данные отправляются одному из устройств: ЦАП(Цифро-аналоговый преобразователь), контроллер PMBUS, КМБО(Канал МежБлочного Обмена) и внутреннему регистру.
module kon(mosi, oena0, oena1, oena2, oena3, data, ena, clk); parameter DW = 16; // битовая длина шин input [(DW - 1): 0] data; // шина данных input ena, clk; // сигнал включения и тактовый сигнал output [(DW - 1): 0] mosi;// сигнал MOSI(Master Out Slave In) // выходные сигналы включения интерфейса SPI output oena0, oena1, oena2, oena3; // с тирггером на выходе reg oena0, oena1, oena2, oena3; reg [(DW - 1): 0] addr; // адрес команды reg ffbit; // флаг первого слова потока reg [4:0] sch_we, sch_re; // счетчики assign eram = ena & ~ffbit; // сигнал включения записи в память // экземпляр модуля памяти tram ram(data, clk, eram, sch_we, sch_re, mosi); always @(posedge clk) begin if (ena) begin // обнуление sch_re <= 0; oena0 <= 0; oena1 <= 0; oena2 <= 0; oena3 <= 0; if (ffbit) begin // первым словом ловим адресс addr <= data; ffbit <= 0; end else begin // увеличиваем счетчик записи sch_we <= sch_we + 1; end end else begin // обнуление ffbit <= 1; sch_we <= 0; // выбор подчиненного устройства SPI case (addr) 0: begin // отправляет цап oena0 <= 1; end 1: begin // отправляет Контроллеру PMBUS oena1 <= 1; end 2: begin // отправляет КМБО oena2 <= 1; end default: begin // отправляет внутреннему регистру oena3 <= 1; end endcase // увелииваем счетчик чтения памяти sch_re <= sch_re + 1; end end endmodule // память module tram(data, clk, we, addr_we, addr_re, out); parameter DW = 16; parameter AW = 4; input [(DW - 1): 0] data; input [(AW - 1): 0] addr_we, addr_re; input clk, we; output reg [(DW - 1): 0] out; reg [(DW - 1): 0] ram [(2**AW - 1): 0]; always @(posedge clk) begin if (we) ram[addr_we] <= data; out = ram[addr_re]; end endmodule

Делить тактовой частоты на 5 c сase

Делитель тактовой частоты на дробное число возможно организовать только с помощью построения собственного счетчика, которого невозможно прописать без оператора case. Также важным элементом является запаздывающий сигнал. Временная диаграмма показаны на рисунке 1.

Временная диаграмма делителя на 5
Рисунок 1. Временная диаграмма делителя 5.
Принцип работы модуля: при каждом восходящем фронте тактового сигнала sig меняется значение счетчика sch написанного на case. Если значение достигается 3, на запаздывающий сигнала dl_sig подается высокий уровень на один такт низпадающего фронта. Дизъюнкция sch[0] и dl_sig дает деленный сигнал на 5.
module div5x0(out, sig, reset); input sig; // тактовый сигнал input reset; // асинхронный сброс output out; // деленный тактовый сигнал reg [2:0] sch = 1; // собственный счетчик reg dl_sig = 0; // запаздывающий сигнал always @(posedge sig, posedge reset) begin if (reset) begin // сброс sch <= 1; end else begin // логика счетчика case (sch) 1: sch <= 3; 3: sch <= 4; 4: sch <= 2; 2: sch <= 6; 6: sch <= 1; default: sch <= 1; endcase end end always @(negedge sig, posedge reset) begin if (reset) begin // сброс dl_sig <= 0; end else begin // логика запаздывающего сигнала if (sch == 3) begin dl_sig <= 1; end else begin dl_sig <= 0; end end end assign out = sch[0] | dl_sig; endmodule