Последовательный вывод на индикаторах:
1.Z-состояние.
2.'____' (состояние ожидания; b1110111).
3.'□□□□' (состояние чтения; b0011100).
4.'EEEE' (состояние ошибки, мало средств; b0000110).
5.'____' (состояние ожидания; b1110111).
6.'□□□□' (состояние чтения; b0011100).
7.'9954' (состояние отображение информации о новом балансе карты: вместо 9954 может быть и другое число; в данном случае от текущего баланса 9999 рублей отнимается стоимость прохода 45 рублей).
8.'____' (состояние ожидания; b1110111).
Код программы
Таблица 1. Файл кодера
|
Вспомогательный кодер: MetroCoder.v |
module MetroCoder |
|
(input wire [3:0] |
in4, |
output reg [6:0] out7); |
|
always @* |
|
case (in4) |
|
4'b0000: out7 |
= 7'b1000000; // '0' |
4'b0001: out7 |
= 7'b1111001; // '1' |
4'b0010: out7 |
= 7'b0100100; // '2' |
4'b0011: out7 |
= 7'b0110000; // '3' |
4'b0100: out7 |
= 7'b0011001; // '4' |
4'b0101: out7 |
= 7'b0010010; // '5' |
4'b0110: out7 |
= 7'b0000010; // '6' |
4'b0111: out7 |
= 7'b1111000; // '7' |
4'b1000: out7 |
= 7'b0000000; // '8' |
4'b1001: out7 |
= 7'b0010000; // '9' |
4'b1010: out7 |
= 7'b1110111; // '_' |
4'b1011: out7 |
= 7'b0011100; // '□' (wait) |
4'b1100: out7 |
= 7'b0000110; // 'E' (error) |
4'b1101: out7 |
= 7'b1110111; // '_' |
4'b1110: out7 |
= 7'b1110111; // '_' |
4'b1111: out7 |
= 7'b1110111; // '_' |
endcase |
|
endmodule |
|
|
|
|
Таблица 2. Файл устройства |
|
|
|
Файл устройства: MetroFSM.v |
module MetroFSM |
|
//Параметр CODE_BITS означает количество бит для описания кода
//Параметр MONEY_BITS означает количество бит для описания денег
#(parameter CODE_BITS = 6, MONEY_BITS = 14)
//clk - тактовый сигнал
//ena - разрешение счета
//res - синхронный сброс
//reset - асинхронный сброс
//code - код для проверки
//indicators - индикаторы
(input wire clk, ena, res, reset, input wire isCardAttached,
input wire [MONEY_BITS-1:0] currentBalance, input wire [CODE_BITS-1:0] code,
output reg permission,
output wire [6:0] indicators [3:0]);
6
// Состояния |
|
|
parameter |
INITIAL_STATE = 0; |
|
parameter |
CARD_WAITING_STATE = |
1; |
parameter |
CARD_READING_STATE = |
2; |
parameter |
CARD_DISPLAY_STATE = |
3; |
parameter |
ENTRY_PERMIT_STATE = |
4; |
parameter |
CARD_READING_ERROR_STATE = 5; |
|
// Индикаторы |
|
|
reg [3:0] |
in4 [3:0]; |
|
MetroCoder cdr1 (.in4(in4[0]), |
.out7(indicators[0])); |
|
MetroCoder cdr2 (.in4(in4[1]), |
.out7(indicators[1])); |
|
MetroCoder cdr3 (.in4(in4[2]), |
.out7(indicators[2])); |
|
MetroCoder cdr4 (.in4(in4[3]), |
.out7(indicators[3])); |
|
//Состояние, счет, доп. переменные и стоимость проезда reg [2:0] state = INITIAL_STATE;
reg [3:0] cnt = 0; reg s;
reg [CODE_BITS-2:0] i, endi = CODE_BITS >> 1;
reg [MONEY_BITS-1:0] price = 6'b101101, newBalance;
//Управление асинхронным сбросом
always@ (posedge clk or negedge reset) |
|
||
if (!reset) |
begin |
|
|
state <= INITIAL_STATE; |
|
||
cnt <= 4'd0; |
|
|
|
end |
|
|
|
// Логика смен состояний |
|
|
|
always@ (posedge clk or posedge reset) |
|
||
if (res) begin |
|
|
|
state <= INITIAL_STATE; |
|
||
cnt <= 4'd0; |
|
|
|
end |
|
|
|
else case (state) |
|
|
|
INITIAL_STATE: begin |
|
||
|
// Переход к |
состоянию ожидания |
|
|
in4[0] = 4'b1010; // |
'_' |
|
|
in4[1] = 4'b1010; // |
'_' |
|
|
in4[2] = 4'b1010; // |
'_' |
|
|
in4[3] = 4'b1010; // '_' |
|
|
|
permission = |
1'b0; |
|
|
state <= CARD_WAITING_STATE; |
||
end |
|
|
|
CARD_WAITING_STATE: |
|
||
|
// Переход к |
чтению, если 2 такта прошло |
|
|
if (cnt == 4'd2) begin |
|
|
|
in4[0] = |
4'b1011; // |
'□' |
|
in4[1] = |
4'b1011; // |
'□' |
|
in4[2] = |
4'b1011; // |
'□' |
|
in4[3] = |
4'b1011; // '□' |
|
|
state <= |
CARD_READING_STATE; |
|
|
end |
|
|
CARD_READING_STATE: |
|
||
|
// Если карта не приложена, то переход к отображению ошибки |
||
|
if (!isCardAttached) begin |
||
|
in4[0] = |
4'b1100; // |
'E' |
|
in4[1] = |
4'b1100; // |
'E' |
|
in4[2] = |
4'b1100; // |
'E' |
|
in4[3] = |
4'b1100; // 'E' |
|
|
state <= |
CARD_READING_ERROR_STATE; |
|
|
end |
|
|
|
// Переход к |
проверке, если 2 такта прошло |
|
|
else if (cnt |
== 4'd4) begin |
|
//Проверка кода и баланса
//Проверка кода: код верный, если старшие биты кода
противоположны младшим битам
// Т. е. если биты n, ..., n/2 противоположны n/2-1, ..., 0 s = 1;
7
for (i = 0; i < endi; i = i + 1'b1)
s= s & (code[i] ^ code[i + endi]);
//Проверка баланса: если меньше, то выход с ошибкой if (currentBalance < price || !s) begin
in4[0] = 4'b1100; // |
'E' |
in4[1] = 4'b1100; // |
'E' |
in4[2] = 4'b1100; // |
'E' |
in4[3] = 4'b1100; // 'E' |
|
state <= CARD_READING_ERROR_STATE; |
|
end |
|
else begin |
|
// Перевод числа из двоичной в десятичную для индикаторов |
|
newBalance = currentBalance - price; |
|
i = 0; |
|
while (newBalance >= 1000) begin |
|
newBalance = newBalance - 1000; |
|
i = i + 1; |
|
end |
|
in4[3] = i; |
|
i = 0; |
|
while (newBalance >= 100) begin |
|
newBalance = newBalance - 100; |
|
i = i + 1; |
|
end |
|
in4[2] = i; i = 0;
while (newBalance >= 10) begin newBalance = newBalance - 10; i = i + 1;
end
in4[1] = i;
in4[0] = newBalance;
state <= CARD_DISPLAY_STATE;
end
end
CARD_DISPLAY_STATE:
// Переход к разрешению входа, если 3 такта прошло if (cnt == 4'd7) begin
permission <= 1'b1;
state <= ENTRY_PERMIT_STATE;
end |
|
|
|
ENTRY_PERMIT_STATE: begin |
|
||
in4[0] |
= |
4'b1010; // |
'_' |
in4[1] |
= |
4'b1010; // |
'_' |
in4[2] |
= |
4'b1010; // |
'_' |
in4[3] |
= |
4'b1010; // '_' |
|
permission = 1'b0; |
|
||
state <= |
CARD_WAITING_STATE; |
||
end |
|
|
|
CARD_READING_ERROR_STATE: begin |
|||
in4[0] |
= |
4'b1010; // |
'_' |
in4[1] |
= |
4'b1010; // |
'_' |
in4[2] |
= |
4'b1010; // |
'_' |
in4[3] |
= |
4'b1010; // '_' |
|
state <= |
CARD_WAITING_STATE; |
||
end |
|
|
|
endcase |
|
|
|
// Логика действий внутри состояний |
|
||
always@ (posedge clk) |
|
|
|
if (res) begin |
|
|
|
state <= INITIAL_STATE; |
|
||
cnt <= 4'd0; |
|
|
|
end |
|
|
|
else if (ena) case |
(state) |
|
|
INITIAL_STATE: |
begin |
|
|
cnt <= |
4'd0; |
|
|
8
end
CARD_WAITING_STATE: begin
cnt <= (isCardAttached ? cnt + 4'd1 : 4'd0);
end
CARD_READING_STATE: begin cnt <= cnt + 4'd1;
end
CARD_DISPLAY_STATE: begin cnt <= cnt + 4'd1;
end
ENTRY_PERMIT_STATE: begin cnt <= 4'd0;
end
CARD_READING_ERROR_STATE: begin cnt <= 4'd0;
end endcase
endmodule
Таблица 3. Тестбенч-файл
Тестбенч: MetroFSM_TB.v
`timescale 1ns/10ps module MetroFSM_TB;
localparam T = 20, CODE_BITS = 6, MONEY_BITS = 14; reg clk, ena, res = 1'b0, reset, isCardAttached; reg [CODE_BITS-1:0] code;
wire permission;
wire [6:0] indicators [3:0];
reg [MONEY_BITS-1:0] currentBalance = 0;
MetroFSM machine(.clk(clk), .ena(ena), .res(res), .reset(reset),
.isCardAttached(isCardAttached), .currentBalance(currentBalance), .code(code),
.permission(permission), .indicators(indicators)); always
begin
clk = 1'b0; #(T / 2); clk = 1'b1; #(T / 2);
end always begin
ena = 1'b0; #(T / 2); ena = 1'b1; #(T / 2);
end initial begin
reset = 1'b0; #(T / 4); reset = 1'b1; isCardAttached = 1'b1;
end initial begin
code = 6'b000111; isCardAttached = 1'b0; currentBalance = 0; repeat(5) @(negedge clk); isCardAttached = 1'b0; @(negedge clk); isCardAttached = 1'b1;
currentBalance = 14'b10011100001111; repeat(10) @(negedge clk);
res = 1'b1;
repeat(2) @(negedge clk); $stop;
end endmodule
9
СПИСОК ЛИТЕРАТУРЫ
1.Неелова О. Л. Лекции по дисциплине «Программное проектирование элементов вычислительных систем».
2.Автоматы Мили и Мура [Электронный ресурс]. – Режим доступа: https://neerc.ifmo.ru/wiki/index.php?title=Автоматы_Мура_и_Мили, свободный –
(29.05.2020).
3.Угрюмов Е. П. Цифровая схемотехника: учеб. пособие для вузов. — 3-е изд.,
перераб. и доп. — СПб.: БХВ-Петербург, 2010. — 816 с.: ил.
10