FSM Design T5
实现两层的简易电梯指示灯系统。电梯有4个按键:1楼外的向上按键(A0),2楼外的向下按键(A1),电梯内的1楼和2楼按键(F1和F2)。电梯有4个指示灯:
L0:按下A0键,若电梯不在1楼,则L0亮。
L1:按下A1键,若电梯不在2楼,则L1亮。
L2:电梯在2楼,按F1键, 则L2亮,电梯到1楼后L2灭。
L3:电梯在1楼,按F2键, 则L3亮,电梯到2楼后L3灭。
注:输入信号至少包含reset和clock,A0、A1、F1、F2为电梯的4个按键,L0~L3分别为电梯的四个指示灯,请同学们按照此命名编写Verilog代码。
1. Analysis
根据题目中描述的电梯按键及电梯信号灯,可以将四个电梯按键A0、A1、F1、F2作为逻辑输入变量,将四个电梯信号灯L0、L1、L2、L3作为逻辑输出变量。假设按下电梯键为1、不按电梯键为0,电梯信号灯亮为1、电梯信号灯不亮为0,现设置表征电梯所在楼层数的状态变量S1(电梯现位于一楼)、S2(电梯现位于二楼),利用Mealy类型的FSM(状态机输出和当前状态、输入信号均有关)可以实现题中需求。
考虑到A0、A1、F1、F2等按键的时间可长可短,即:按键可以按下一段较长的时间,也可以按下一段较短的时间,但是无论时间的长短,以上任意的按键一旦按下,则电梯、信号灯必须作出相应的反应,只有这样才符合实际生活的常识。因此,本文设计了keep变量,用于检测A0、A1、F1、F2的电平变化,并将FSM的下一状态保存在keep寄存器中。本文设计了四个不同的testbench测试文件,其区别在于A0、A1、F1、F2等按键的时间长短不同,以测试、验证Verilog代码的健壮性。
2. FSM Diagram
3. Port List
Port Name | Attribute | Width | Meaning |
---|---|---|---|
clock | input | 1 bit | 时钟信号 |
reset | input | 1 bit | 复位信号 |
A0, A1, F1, F2 | input | 1 bit | 电梯按键输入信号 |
L0, L1, L2, F3 | output | 1 bit | 电梯信号灯输出信号 |
4. Verilog Code
`timescale 1ns/1ps
module exercise5 (CLK, RST, A0, A1, F1, F2, L0, L1, L2, L3);
input wire CLK;
input wire RST;
input wire A0, A1, F1, F2;
output reg L0, L1, L2, L3;
reg cs;
reg ns;
reg keep;
parameter s0 = 1'b0;
parameter s1 = 1'b1;
always @ (posedge CLK or negedge RST) begin
if (!RST) begin
cs <= s0;
end
else begin
cs <= ns;
end
end
always @ (*) begin
if (!RST) begin
keep = s0;
end
else begin
case (cs)
s0: begin
if ((F2 == 1'b1) || (A1 == 1'b1)) begin
keep = s1;
ns = keep;
end
else begin
ns = keep;
end
end
s1: begin
if ((F1 == 1'b1) || (A0 == 1'b1)) begin
keep = s0;
ns = keep;
end
else begin
ns = keep;
end
end
default: begin
keep = s0;
ns = s0;
end
endcase
end
end
always @ (*) begin
case (cs)
s0: begin
L0 = 1'b0;
L2 = 1'b0;
if (A1 == 1'b1) begin
L1 = 1'b1;
end
else if (F2 == 1'b1) begin
L3 = 1'b1;
end
else begin
L1 = L1;
L3 = L3;
end
end
s1: begin
L1 = 1'b0;
L3 = 1'b0;
if (A0 == 1'b1) begin
L0 = 1'b1;
end
else if (F1 == 1'b1) begin
L2 = 1'b1;
end
else begin
L0 = L0;
L2 = L2;
end
end
default: begin
L0 = 1'b0;
L1 = 1'b0;
L2 = 1'b0;
L3 = 1'b0;
end
endcase
end
endmodule
5. Testbench Code
`timescale 1ns/1ps
module exercise5_test;
reg CLK;
reg RST;
reg A0, A1, F1, F2;
wire L0, L1, L2, L3;
parameter half_cycle = 5;
parameter s0 = 1'b0;
parameter s1 = 1'b1;
exercise5 exercise5_inst (
.CLK(CLK),
.RST(RST),
.A0(A0),
.A1(A1),
.F1(F1),
.F2(F2),
.L0(L0),
.L1(L1),
.L2(L2),
.L3(L3)
);
initial begin
CLK = 0;
forever begin
CLK = # half_cycle ~ CLK;
end
end
initial begin
RST = 1;
# (1 * half_cycle) RST = 0;
# (2 * half_cycle) RST = 1;
end
initial begin
A0 = 0;
A1 = 0;
F1 = 0;
F2 = 0;
# (4 * half_cycle) A1 = 1;
# (2 * half_cycle) A1 = 0;
# (4 * half_cycle) F1 = 1;
# (2 * half_cycle) F1 = 0;
# (4 * half_cycle) F2 = 1;
# (2 * half_cycle) F2 = 0;
# (4 * half_cycle) A0 = 1;
# (2 * half_cycle) A0 = 0;
end
//initial begin
// A0 = 0;
// A1 = 0;
// F1 = 0;
// F2 = 0;
// # (4 * half_cycle) A1 = 1;
// # (1 * half_cycle) A1 = 0;
// # (3 * half_cycle) F1 = 1;
// # (1 * half_cycle) F1 = 0;
// # (3 * half_cycle) F2 = 1;
// # (1 * half_cycle) F2 = 0;
// # (3 * half_cycle) A0 = 1;
// # (1 * half_cycle) A0 = 0;
//end
//initial begin
// A0 = 0;
// A1 = 0;
// F1 = 0;
// F2 = 0;
// # (4 * half_cycle) A1 = 1;
// # (0.6 * half_cycle) A1 = 0;
// # (4 * half_cycle) F1 = 1;
// # (0.6 * half_cycle) F1 = 0;
// # (4 * half_cycle) F2 = 1;
// # (0.6 * half_cycle) F2 = 0;
// # (4 * half_cycle) A0 = 1;
// # (0.6 * half_cycle) A0 = 0;
//end
//initial begin
// A0 = 0;
// A1 = 0;
// F1 = 0;
// F2 = 0;
// # (4 * half_cycle) A1 = 1;
// # (0.2 * half_cycle) A1 = 0;
// # (4 * half_cycle) F1 = 1;
// # (0.2 * half_cycle) F1 = 0;
// # (4 * half_cycle) F2 = 1;
// # (0.2 * half_cycle) F2 = 0;
// # (4 * half_cycle) A0 = 1;
// # (0.2 * half_cycle) A0 = 0;
//end
initial begin
# (100 * half_cycle) $finish;
end
initial begin
$fsdbDumpfile("./verdiFsdb/exercise5.fsdb");
$fsdbDumpvars(0);
end
endmodule