
Отчёт к лабораторной работе №5
“Сборка и проверка работоспособности многомодульного устройства”
Введение
Цель данной лабораторной работы — разработать и смоделировать многомодульное устройство на языке Verilog по заданной схеме. Устройство состоит из нескольких модулей, таких как защелки, кодер, буфер, мультиплексор и конечный автомат. В отчете представлены все этапы моделирования, включая блок-схемы модулей и функциональные диаграммы.
Описание устройств
Устройство предназначено для приема 4-битных входных данных, их обработки и передачи на выходной модуль parser. Основные компоненты устройства:
Защелка (latch): хранит входные данные.
Кодер (coder4x5): преобразует 4-битные данные в 5-битные.
Буфер (bufer5x4): временно хранит данные для дальнейшей обработки.
Мультиплексор (mpl): выбирает один из нескольких входов для передачи на выход.
Конечный автомат (fsm): управляет работой устройства, контролируя сигналы записи и чтения, а также выбирая команды для мультиплексора.
Функциональная схема кодера 4x5:
Модуль coder4x5
Назначение
Модуль coder4x5 предназначен для преобразования 4-битного входного сигнала data4 в 5-битный выходной сигнал data5 на основе предопределенной таблицы кодирования. Это позволяет расширить разрядность данных и выполнить определенное кодирование для последующей обработки.
Входы и выходы
Входы:
data4[3:0]: 4-битный входной сигнал.
Выходы:
data5[4:0]: 5-битный выходной сигнал.
Код:
module coder4x5 (
input wire [3:0] data4,
output wire [4:0] data5
);
reg [4:0] code; // для хранения состояний выходов
assign data5 = code;
always @* begin
case (data4)
4'b0000: code = 5'b11110;
4'b0001: code = 5'b01001;
4'b0010: code = 5'b10100;
4'b0011: code = 5'b10101;
4'b0100: code = 5'b01010;
4'b0101: code = 5'b01011;
4'b0110: code = 5'b01110;
4'b0111: code = 5'b01111;
4'b1000: code = 5'b10010;
4'b1001: code = 5'b10011;
4'b1010: code = 5'b10110;
4'b1011: code = 5'b10111;
4'b1100: code = 5'b11010;
4'b1101: code = 5'b11011;
4'b1110: code = 5'b11100;
4'b1111: code = 5'b11101;
default: code = 5'b00000; // значение по умолчанию на случай ошибки
endcase
end
endmodule
Функциональная схема мультиплексора:
Модуль mpl (Мультиплексор)
Назначение
Модуль mpl реализует 4-входовый мультиплексор, который на основе управляющего сигнала send_cmd выбирает один из четырех 5-битных входов и передает его на выход line.
Входы и выходы
Входы:
in0[4:0]: Первый входной сигнал.
in1[4:0]: Второй входной сигнал.
in2[4:0]: Третий входной сигнал.
in3[4:0]: Четвертый входной сигнал.
send_cmd[1:0]: 2-битный управляющий сигнал для выбора одного из входов.
Выходы:
line[4:0]: Выбранный выходной сигнал.
Код:
module mpl (
input [4:0] in0, // ???? 0 (5-?????????)
input [4:0] in1, // ???? 1 (5-?????????)
input [4:0] in2, // ???? 2 (5-?????????)
input [4:0] in3, // ???? 3 (5-?????????)
input [1:0] send_cmd, // ??????? ?????? (2 ???? ??? ?????? ?????? ?? 4 ??????)
output [4:0] line // ???????? ????? (5-?????????)
);
reg [4:0] mux_out; // ?????? ??? ???????? ?????????? ????? (?????? ????? cell)
// ???????????? ???????? mux_out ???????? ?????
assign line = mux_out;
// ???? always ??? ???????????? ???????? ? ??????????? ?? ???????
always @(*) begin
case (send_cmd)
2'b00: mux_out = in0; // ???? ??????? 00, ?? ????? ?????????? in0
2'b01: mux_out = in1; // ???? ??????? 01, ?? ????? ?????????? in1
2'b10: mux_out = in2; // ???? ??????? 10, ?? ????? ?????????? in2
2'b11: mux_out = in3; // ???? ??????? 11, ?? ????? ?????????? in3
default: mux_out = 5'b00000; // ???????? ?? ????????? ? 5 ?????
endcase
end
endmodule
Модуль latch (Защелка)
Функциональная схема защёлки:
Назначение
Модуль latch предназначен для хранения входных данных при нарастании тактового сигнала clk. Это стандартная D-защелка.
Параметры
parameter N = 4: Параметризированная ширина входных и выходных данных.
Входы и выходы
Входы:
clk: Тактовый сигнал.
d_in[N-1:0]: Входные данные шириной N бит.
Выходы:
d_out[N-1:0]: Выходные данные шириной N бит.
Код:
`timescale 1ns/100ps
module latch #(parameter N = 4) (
input wire clk,
input wire [N-1:0] d_in,
output reg [N-1:0] d_out
);
always @(posedge clk) begin
d_out <= d_in;
end
endmodule
Модуль bufer5x4 (Буфер)
Функциональная схема буфера
Назначение
Модуль bufer5x4 реализует сдвиговый регистр или буфер глубиной 4, который хранит последовательность из четырех 5-битных значений. Он позволяет записывать новые данные и читать их в порядке поступления.
Входы и выходы
Входы:
clk: Тактовый сигнал.
reset: Сигнал сброса.
wr: Сигнал разрешения записи.
rd: Сигнал разрешения чтения.
data_in[4:0]: Входные данные.
Выходы:
data_out[4:0]: Выходные данные.
Код:
module bufer5x4 (
input wire clk, // ???????? ??????
input wire reset, // ?????? ??????
input wire wr, // ?????????? ??????
input wire rd, // ?????????? ??????
input wire [4:0] data_in, // ??????? ??????
output wire [4:0] data_out // ???????? ??????
);
// ?????????? ??????????
reg [4:0] shift_reg[3:0]; // 4 ??????????? ?????? ??? ???????? ??????
integer i;
// ??????????? ????? ???????? ????????? ??????
assign data_out = shift_reg[3];
// ???? ??????, ? ????????????????? ? posedge clk ? posedge reset
always @(posedge clk or posedge reset) begin
if (reset) begin
// ??? ?????? ???????? ??? ????????
for (i = 0; i < 4; i = i + 1) begin
shift_reg[i] <= 5'd0;
end
end else begin
// ?????? ?????? (wr) ??? ?????? (rd)
if (wr) begin
// ?????????? ?????? ?? ??? ?????? ??????
for (i = 1; i < 4; i = i + 1) begin
shift_reg[i] <= shift_reg[i-1];
end
shift_reg[0] <= data_in;
end else if (rd) begin
// ???????? ?????? ?? ?????
for (i = 1; i < 4; i = i + 1) begin
shift_reg[i] <= shift_reg[i-1];
end
shift_reg[0] <= 5'd0; // ???????? ?? ???? ??? ??????
end
end
end
endmodule
Модуль fsm (Конечный автомат)
Функциональная схема конечного автомата:
Назначение
Модуль fsm реализует конечный автомат, который управляет процессами записи и чтения данных, а также взаимодействием с мультиплексором и буфером. Он определяет последовательность действий в зависимости от текущего состояния и входных сигналов.
Входы и выходы
Входы:
clk: Тактовый сигнал.
Reset (res): Сигнал сброса.
data_wr (wr_en): Сигнал разрешения записи данных.
Выходы:
buf_wr: Сигнал записи в буфер.
buf_rd: Сигнал чтения из буфера.
adr[1:0]: Управляющий сигнал для мультиплексора.
state[2:0]: Текущее состояние автомата.
data_cnt[3:0]: Счетчик количества записанных данных.
Код:
module fsm(
input clk, // Синхроимпульс
input reset, // Сигнал сброса
input data_wr, // Сигнал разрешения записи
output reg wr, // Сигнал записи
output reg rd, // Сигнал чтения
output reg [1:0] adr // Адрес для мультиплексора
);
// Внутренние регистры
reg [2:0] state; // Регистр состояния
reg [3:0] data_cnt; // Регистр счетчика буфера (должен считать до 4)
// Определение параметров для состояний
parameter S0 = 3'd0,
S1 = 3'd1,
S2 = 3'd2,
S3 = 3'd3,
S4 = 3'd4,
S5 = 3'd5,
S6 = 3'd6;
// Определение параметров для команд
parameter CMD_START = 2'b00,
CMD_DATA = 2'b01,
CMD_STOP = 2'b10,
CMD_IDLE = 2'b11;
// Блок формирования смены состояний (переходов)
always @(posedge clk or posedge reset)
begin
if (reset)
state <= S0; // Сброс в начальное состояние
else
begin
case (state)
S0: state <= S1; // После сброса переход в S1
S1: if (data_wr)
state <= (data_cnt == 4) ? S4 : S2; // Если data_cnt=4, переходим в S4 (стартовая посылка), иначе в S2 (запись данных)
else
state <= S1; // Ожидание разрешения записи
S2: if (data_cnt < 4)
state <= S2; // Продолжаем запись данных, пока data_cnt < 4
else
state <= S4; // Переход в стартовую посылку после завершения записи
S4: state <= S5; // Переход в S5 для стартовой посылки
S5: if (data_cnt == 1)
state <= S6; // Если data_cnt=1, переход в стоповую посылку
else
state <= S5; // Продолжение посылки данных
S6: state <= S1; // Переход обратно в S1 после стоповой посылки
default: state <= S0; // Защита на случай неизвестного состояния
endcase
end
end
// Блок описания действий исполнительного устройства
always @(posedge clk or posedge reset)
begin
if (reset)
begin
wr <= 1'b0;
rd <= 1'b0;
adr <= CMD_IDLE;
data_cnt <= 4'd0; // Счетчик должен обнуляться при сбросе
end
else
begin
case (state)
S0: // Состояние сброса
begin
wr <= 1'b0;
rd <= 1'b0;
adr <= CMD_IDLE;
data_cnt <= 4'd0; // Обнуление счетчика в состоянии сброса
end
S1: // Ожидание разрешения записи
begin
wr <= 1'b0;
rd <= 1'b0;
adr <= CMD_IDLE;
end
S2: // Запись данных
begin
wr <= 1'b1; // Установка сигнала записи
rd <= 1'b0; // Сигнал чтения должен быть 0
adr <= CMD_DATA; // Установка адреса для передачи данных
if (data_cnt < 4)
data_cnt <= data_cnt + 1; // Увеличение счетчика, пока он меньше 4
end
S4: // Стартовая посылка
begin
wr <= 1'b0;
rd <= 1'b0;
adr <= CMD_START; // Установка адреса для стартовой посылки
end
S5: // Посылка данных
begin
wr <= 1'b0; // Сигнал записи должен быть 0
rd <= 1'b1; // Установка сигнала чтения
adr <= CMD_DATA; // Установка адреса для передачи данных
if (data_cnt > 1)
data_cnt <= data_cnt - 1; // Уменьшение счетчика
else
data_cnt <= 4'd0; // Обнуление счетчика, когда data_cnt <= 1
end
S6: // Стоповая посылка
begin
wr <= 1'b0;
rd <= 1'b0;
adr <= CMD_STOP; // Установка адреса для стоповой посылки
data_cnt <= 4'd0; // Обнуление счетчика в конце
end
default: // Защита на случай неизвестного состояния
begin
wr <= 1'b0;
rd <= 1'b0;
adr <= CMD_IDLE;
data_cnt <= 4'd0;
end
endcase
end
end
endmodule
Модуль controller (Контроллер)
Функциональная схема контроллера:
Назначение
Модуль controller является верхнеуровневым модулем, объединяющим все ранее описанные модули. Он обеспечивает полную функциональность устройства, обрабатывая входные данные, кодируя их, буферизуя и управляя передачей данных на выходной модуль parser.
Входы и выходы
Входы:
clk: Тактовый сигнал.
reset: Сигнал сброса.
data_in[3:0]: Входные данные.
data_wr: Сигнал разрешения записи.
Выходы:
parser_out[4:0]: Выходные данные для модуля parser.
fsm_state[2:0]: Текущее состояние конечного автомата.
Внутренние сигналы
data5[4:0]: Выходные данные от кодера.
buffer_out[4:0]: Выходные данные из буфера.
mpl_out[4:0]: Выход мультиплексора.
latch5_out[4:0]: Выходная защелка.
buf_write: Сигнал записи в буфер.
buf_read: Сигнал чтения из буфера.
send_cmd[1:0]: Команда для мультиплексора.
data_cnt[3:0]: Счетчик данных из FSM.
state_fsm[2:0]: Текущее состояние FSM.
Симуляция контроллера.
// controller.v
`timescale 1ns/1ps
module controller (
input wire clk, // Тактовый сигнал
input wire reset, // Сигнал сброса
input wire [3:0] data_in, // Входные данные (4-битные)
input wire data_wr, // Сигнал разрешения записи
output wire [4:0] parser_out, // Выходные данные на модуль parser
output wire [2:0] fsm_state // Новый выход для состояния FSM
);
// Внутренние сигналы
wire [4:0] data5;
wire [4:0] buffer_out;
wire [4:0] mpl_out;
wire [4:0] latch5_out;
wire buf_write, buf_read;
wire [1:0] send_cmd;
wire [3:0] data_cnt;
wire [2:0] state_fsm; // Внутренний сигнал для состояния FSM
// Модуль защелки для хранения входных данных
wire [3:0] data_out_rgstr;
latch #(.N(4)) latch_rgstr_inst (
.clk(clk),
.d_in(data_in),
.d_out(data_out_rgstr)
);
// Модуль кодера
coder4x5 coder_inst (
.data4(data_out_rgstr), // Используем данные из защёлки
.data5(data5)
);
// Модуль буфера
bufer5x4 buffer_inst (
.clk(clk),
.reset(reset),
.wr(buf_write),
.rd(buf_read),
.data_in(data5),
.data_out(buffer_out)
);
// Мультиплексор
mpl mpl_inst (
.in0(5'b00110),
.in1(data5),
.in2(5'b01101), // CMD_START
.in3(5'b11111), // CMD_STOP
.send_cmd(send_cmd),
.line(mpl_out)
);
// Защелка для регистрации данных из мультиплексора
latch #(.N(5)) latch5_inst (
.clk(clk),
.d_in(mpl_out),
.d_out(latch5_out)
);
// Конечный автомат
fsm fsm_inst (
.clk(clk),
.reset(reset),
.data_wr(data_wr), // Подключаем внешний сигнал
.buf_wr(buf_write),
.buf_rd(buf_read),
.adr(send_cmd),
.state(state_fsm), // Подключение сигнала state
.data_cnt(data_cnt)
);
// Присваиваем внутренний сигнал выходу
assign fsm_state = state_fsm;
// Модуль parser (предполагается, что он реализован отдельно)
// Подключение выхода из latch5 к parser
// Если модуль parser отсутствует, можно напрямую присвоить:
assign parser_out = latch5_out;
endmodule
Тестбенч для модуля контоллера:
// controller_tb.v
`timescale 1ns/1ps
module controller_tb;
// Входы
reg clk;
reg reset;
reg [3:0] data_in;
reg data_wr; // Сигнал разрешения записи
// Выходы
wire [4:0] parser_out;
wire [2:0] fsm_state; // Выход состояния FSM
// Параметры тактового сигнала
parameter PERIOD = 10;
// Инстанцирование верхнеуровневого модуля
controller uut (
.clk(clk),
.reset(reset),
.data_in(data_in),
.data_wr(data_wr), // Подключаем сигнал data_wr
.parser_out(parser_out),
.fsm_state(fsm_state) // Подключение нового выхода
);
// Генерация тактового сигнала
initial begin
clk = 0;
forever #(PERIOD/2) clk = ~clk;
end
// Инициализация и тестирование
initial begin
// Инициализация входов
reset = 1;
data_in = 4'b0000;
data_wr = 0; // Изначально запись запрещена
#(PERIOD);
// Сброс
reset = 0;
#(PERIOD);
// Цикл записи данных
// Для каждой записи:
// 1. Разрешить запись (data_wr = 1)
// 2. Установить данные на data_in
// 3. Удерживать состояние записи на 2 такта
// 4. Запретить запись на 10-15 тактов
// Запись 1
@(posedge clk);
data_in = 4'b0001; // Данные для записи
data_wr = 1; // Разрешаем запись
#(2 * PERIOD); // Удерживаем на 2 такта
data_wr = 0; // Запрещаем запись
#(12 * PERIOD); // Запрет на 12 тактов
// Запись 2
@(posedge clk);
data_in = 4'b0010;
data_wr = 1;
#(2 * PERIOD);
data_wr = 0;
#(12 * PERIOD);
// Запись 3
@(posedge clk);
data_in = 4'b0011;
data_wr = 1;
#(2 * PERIOD);
data_wr = 0;
#(12 * PERIOD);
// Запись 4
@(posedge clk);
data_in = 4'b0100;
data_wr = 1;
#(2 * PERIOD);
data_wr = 0;
#(12 * PERIOD);
// Запись 5
@(posedge clk);
data_in = 4'b0101;
data_wr = 1;
#(2 * PERIOD);
data_wr = 0;
#(12 * PERIOD);
// После последней записи, дайте серию повторов для считывания
#(20 * PERIOD);
// Завершение симуляции
$stop;
end
endmodule
Вывод: Было смоделировано устройство, состоящее из нескольких модулей: защёлки, кодера, буфера, мультиплексора и конечного автомата. Устройство принимает 4-битные входные данные по линии data_in и обрабатывает их в соответствии с заданной логикой. После обработки данные выводятся по линии parser_out, обеспечивая взаимодействие с модулем-приёмником. В рамках лабораторной работы №5 были разработаны и протестированы эти модули на языке Verilog, а также реализовано их объединение в единое устройство согласно заданной схеме.