
- •Введение в логическое проектирование аппаратуры Аннотация к курсу
- •Лекция 1 «Схемы без памяти» Введение
- •Схемы из функциональных элементов
- •Представление схем на языке Verilog Общая информация о языке
- •Модули, пример “Hello World”
- •Синтезируемое подмножество языка
- •Логические значения и операции над ними
- •Многоразрядные константы
- •Непрерывное присваивание
- •Операции над битовыми массивами
- •Инстанцирование модулей
- •Лекция 2 «Схемы с памятью» Введение
- •Абстрактный автомат
- •Структурный автомат
- •Триггеры
- •Описание схем с памятью на языке Verilog
- •Моделирование памяти
- •Процедурное присваивание
- •Always-блоки
- •Управляющие конструкции
- •Лекция 3 «Примеры проектирования на языке Verilog»
- •Лекция 4 «Дискретно-событийное моделирование» Введение
- •Дискретно-событийное моделирование аппаратуры Основные понятия
- •Цикл работы симулятора
- •Дельта-задержка
- •Занятие 5: Контрольная работа
Описание схем с памятью на языке Verilog
Рассмотрим пример D-триггера (D flip-flop).
// D-триггер с асинхронным сбросом
module d_flipflop(q, d, clk, rst);
output q;
input d, clk, rst;
reg q; // возможность присваивания
always @(posedge clk or posedge rst) // список чувствительности
if(rst)
q = 1’b0;
else
q = d;
endmodule /* d_flipflop */
Моделирование памяти
Для моделирования памяти обычно используется конструкция reg.
Примеры
reg mem; // один бит
reg mem[0:15]; // 16-разрядный регистр
reg [0:7] mem [0:31]; // 32 8-разрядных регистров
Ключевое слово reg можно использовать как в отношении внутренних данных, так и выходных сигналов (см. пример D-триггера).
Замечание. К регистрам нельзя применять непрерывное присваивание. Непрерывное присваивание можно применять только к проводам (net, в частности, wire). Для регистров следует использовать процедурное присваивание.
Процедурное присваивание
= — блокируемое присваивание;
<= — неблокируемое присваивание.
Примеры
// блокируемое присваивание
a = 1; b = 2;
begin
a = b;
b = a; // a == 2, b == 2
end
// неблокируемое присваивание
a = 1; b = 2;
begin
a <= b;
b <= a; // a == 2, b == 1
end
Always-блоки
Примеры
always // бесконечный цикл
clk = #10 ~clk;
always @(posedge clk) // обработчик события
...
always @(posedge clk or posedge rst) // обработчик нескольких событий
...
// Гонка: возможны разные порядки
always @(posedge clk) a = b;
always @(posedge clk) b = a;
// Гонки нет
always @(posedge clk) a <= b;
always @(posedge clk) b <= a;
Конструкция @(событие1 or ... событиеn) называется списком чувствительности процесса.
Управляющие конструкции
Конструкция if
if(<expression1>) <statement1>;
else if(<expression2>) <statement2>;
...
else <default_statement>;
Конструкция case
case(<expression>)
<alternative1>: <statement1>;
<alternative2>: <statement2>;
...
default: <default_statement>;
endcase
Пример. Мультиплексор 4-в-1.
module mux4_1(out, i0, i1, i2, i3, s1, s0);
output out;
input i0, i1, i2, i3;
input s1, s0;
reg out;
always @(s1 or s0 or i0 or i1 or i2 or i3)
begin
case({s1, s0})
2'b00: out = i0;
2'b01: out = i1;
2'b10: out = i2;
2'b11: out = i3;
default: out = 1'bx;
endcase
end
endmodule /* mux4_1 */
Задание. Описать на языке Verilog модуль управления пешеходным переходом.
`timescale 1s/1ms
Входы: button (импульсный сигнал).
Выходы: r1, y1, g1, r2, y2, g2 (потенциальные сигналы).
Домашнее задание. Модуль управления лифтом. Сформулировать требования. Продумать интерфейс. Описать на языке Verilog. Написать тест.
Лекция 3 «Примеры проектирования на языке Verilog»
В данной лекции будет рассмотрено несколько примеров проектирования аппаратуры. Цель лекции – продемонстрировать (пусть и в несколько упрощенной форме) основные этапы процесса проектирования аппаратуры (поведенческое проектирование и проектирование на уровне регистровых передач).
Пример 0. «Память прямого доступа на 4 слова»
`timescale 1ns/1ps
// RAM consisting of four 32-bit items
module ram(clk, rst, val_rd, val_wr, addr_in, data_in, val_out, data_out, is_ready);
input clk;
input rst;
input val_rd;
input val_wr;
input [1:0] addr_in;
input [31:0] data_in;
output val_out;
output [31:0] data_out;
output is_ready;
reg [31:0] mem0;
reg [31:0] mem1;
reg [31:0] mem2;
reg [31:0] mem3;
reg [31:0] result;
reg [1:0] state;
// State encoding
parameter RAM_IDLE = 2'b00;
parameter RAM_READ = 2'b01;
parameter RAM_WRITE = 2'b10;
parameter RAM_RESULT = 2'b11;
assign is_ready = (state == RAM_IDLE);
assign val_out = (state == RAM_RESULT);
assign data_out = (state == RAM_RESULT) ? result : 32'h0000_0000;
always @(posedge rst)
begin
mem0 <= 32'hXXXX_XXXX;
mem1 <= 32'hXXXX_XXXX;
mem2 <= 32'hXXXX_XXXX;
mem3 <= 32'hXXXX_XXXX;
result <= 32'hXXXX_XXXX;
state <= 2'b00;
end
always @(posedge clk)
begin
if(state == RAM_IDLE)
begin
// Read operation
if(~rst & val_rd)
begin
state <= RAM_READ;
// Multiplexor 4-to-1
case(addr_in)
2'b00: result <= mem0;
2'b01: result <= mem1;
2'b10: result <= mem2;
2'b11: result <= mem3;
endcase
end
// Write operation
else if(~rst & val_wr)
begin
state <= RAM_WRITE;
result <= 32'hXXXX_XXXX;
// Demultiplexor 1-to-4
case(addr_in)
2'b00: mem0 <= data_in;
2'b01: mem1 <= data_in;
2'b10: mem2 <= data_in;
2'b11: mem3 <= data_in;
endcase
end
end
else
begin
if(state == RAM_RESULT)
begin
state <= RAM_IDLE;
end
else
begin
state <= RAM_RESULT;
end
end
end
endmodule /* ram */
Пример 1. «Очередь FIFO»
`timescale 1ns/1ps
// FIFO queue consisting of four 8-bit items
module fifo(clk, rst, val_rd, val_wr, data_in, val_out, data_out, is_full, is_ready);
input clk;
input rst;
input val_rd;
input val_wr;
input [31:0] data_in;
output val_out;
output [31:0] data_out;
output is_full;
output is_ready;
// RAM[i] is available
reg val0, val1, val2, val3;
reg [1:0] addr0;
reg [1:0] addr1;
reg [1:0] addr2;
reg [1:0] addr3;
reg [1:0] last;
wire [1:0] free_addr;
wire [1:0] addr_in;
assign is_full = val0 & val1 & val2 & val3;
assign free_addr = (~val0 ? 2'h0 :
(~val1 ? 2'h1 :
(~val2 ? 2'h2 :
(~val3 ? 2'h3 : 2'hX))));
assign addr_in = val_wr ? free_addr : (val_rd ? addr0 : 2'h0);
ram memory
(
.clk(clk),
.rst(rst),
.val_rd(val_rd),
.val_wr(val_wr),
.addr_in(addr_in),
.data_in(data_in),
.val_out(val_out),
.data_out(data_out),
.is_ready(is_ready)
);
always @(posedge rst)
begin
val0 <= 1'b0;
val1 <= 1'b0;
val2 <= 1'b0;
val3 <= 1'b0;
addr0 <= 2'hX;
addr1 <= 2'hX;
addr2 <= 2'hX;
addr3 <= 2'hX;
last <= 2'h0;
end
always @(posedge clk)
begin
if(~rst & val_wr)
begin
@(val_out);
case(last)
2'h0: begin
addr0 <= free_addr; val0 <= 1'b1; last <= 2'h1;
end
2'h1: begin
addr1 <= free_addr; val1 <= 1'b1; last <= 2'h2;
end
2'h2: begin
addr2 <= free_addr; val2 <= 1'b1; last <= 2'h3;
end
2'h3: begin
addr3 <= free_addr; val3 <= 1'b1; last <= 2'h3;
end
endcase
end
else if(~rst & val_rd)
begin
case(addr0)
2'h0: val0 <= 1'b0;
2'h1: val1 <= 1'b0;
2'h2: val2 <= 1'b0;
2'h3: val3 <= 1'b0;
endcase
case(last)
2'h0: last <= 2'h0;
2'h1: last <= 2'h0;
2'h2: last <= 2'h1;
2'h3: last <= 2'h2;
endcase
@(val_out);
addr0 <= addr1;
addr1 <= addr2;
addr2 <= addr3;
addr3 <= 2'hX;
end
end
endmodule /* fifo */
Домашнее задание. Доделать модуль FIFO, написать базовый тест, результат отправить по почте.