运行环境:VCS + verdi
状态说明:
S0 : 初始状态
S1 : 东西方向绿灯亮,南北方向红灯亮;点亮30周期
S2 : 东西方向黄灯亮,南北方向红灯亮;点亮2 周期
S3 : 东西方向红灯亮,南北方向绿灯亮;点亮30周期
S4 : 东西方向红灯亮,南北方向黄灯亮;点亮2 周期
状态转换说明:
S0 → S1
S1:点亮30周期,进入S2,不足30周期维持S1
S2:点亮2周期,进入S3,不足2周期维持S2
S3:点亮30周期,进入S4,不足30周期维持S3
S4:点亮2周期,进入S1,不足2周期维持S4
代码如下:
如果需要控制时间,自行添加分频器,或者修改tb文件。
module traffic_light (
input clk,
input rst_n,
output [2:0] light_east_west, light_south_north
);
// 红路灯点亮的时间定义
localparam GREEN = 30;
localparam YELLOW = 2;
// 亮灯的颜色定义
localparam dark = 2'b00;
localparam green = 2'b01;
localparam yello = 2'b10;
localparam red = 2'b11;
// 状态定义
parameter S0 = 5'b0_0001; // 初始状态
parameter S1 = 5'b0_0010; // 东西方向绿灯亮,南北方向红灯亮;30周期
parameter S2 = 5'b0_0100; // 东西方向黄灯亮,南北方向红灯亮;2 周期
parameter S3 = 5'b0_1000; // 东西方向红灯亮,南北方向绿灯亮;30周期
parameter S4 = 5'b1_0000; // 东西方向红灯亮,南北方向黄灯亮;2 周期
reg [4:0] status;
reg [4:0] next_status;
reg [7:0] cnt;
// 计数器控制
always @(posedge clk or negedge rst_n) begin
if(!rst_n) cnt <= 8'b0;
else if ( (status == S1 && cnt == GREEN-1 ) ||(status == S2 && cnt == YELLOW-1) ||
(status == S3 && cnt == GREEN-1 ) ||(status == S4 && cnt == YELLOW-1) )
cnt <= 8'b0;
else
cnt <= cnt + 1'b1;
end
// 状态转换
always @(posedge clk or negedge rst_n) begin
if(!rst_n)
status <= S0;
else
status <= next_status;
end
// 状态判断
always @(*) begin
if(!rst_n) begin
next_status = S0;
end
else begin
case(status)
S0 : next_status = S1;
S1 : next_status = (cnt == GREEN-1) ? S2 : S1;
S2 : next_status = (cnt == YELLOW-1) ? S3 : S2;
S3 : next_status = (cnt == GREEN-1) ? S4 : S3;
S4 : next_status = (cnt == YELLOW-1) ? S1 : S4;
default : next_status = S0;
endcase
end
end
reg [2:0] r_light_east_west, r_light_south_north;
// 输出控制
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
r_light_east_west <= dark;
r_light_south_north <= dark;
end
else begin
case(status)
S0 : begin
r_light_east_west <= dark;
r_light_south_north <= dark;
end
S1 : begin
r_light_east_west <= green;
r_light_south_north <= red;
end
S2 : begin
r_light_east_west <= yello;
r_light_south_north <= red;
end
S3 : begin
r_light_east_west <= red;
r_light_south_north <= green;
end
S4 : begin
r_light_east_west <= red;
r_light_south_north <= yello;
end
default: begin
r_light_east_west <= dark;
r_light_south_north <= dark;
end
endcase
end
end
assign light_east_west = r_light_east_west;
assign light_south_north = r_light_south_north;
endmodule
tb文件:
module tb_traffic_light ();
localparam CLK_PERIDO = 20;
reg clk;
reg rst_n;
reg [2:0] light_east_west;
reg [2:0] light_south_north;
traffic_light traffic_light_inst(
.clk (clk),
.rst_n (rst_n),
.light_east_west (light_east_west),
.light_south_north (light_south_north)
);
initial begin
clk = 0;
forever #(CLK_PERIDO / 2) clk = ~clk;
end
initial begin
rst_n = 0;
repeat(4) @(posedge clk);
#(CLK_PERIDO /5);
rst_n = 1;
repeat(500) @(posedge clk);
$finish;
end
initial begin
$dumpfile("traffic_light.fsdb");
$dumpvars(0);
end
endmodule