I am getting my hands on Verilog and FPGA programming. So I wrote a simple module that handles two inputs - button signal and a clock. Initially, it lights up two LEDs and when the user presses and releases the button, it turns those two off and lights up another two. Here is my code thus far (criticism is very welcome):
`timescale 1ns / 1ps
module led_flip_flop(input wire clk,
input wire button,
output wire [3:0] led);
parameter state_on_idle = 3'b000;
parameter state_on_push = 3'b001;
parameter state_on_pop = 3'b010;
parameter state_off_idle = 3'b011;
parameter state_off_push = 3'b100;
parameter state_off_pop = 3'b101;
reg led_sig;
reg [2:0] state;
reg [2:0] next_state;
initial
begin
led_sig = 1'b1;
state = state_on_idle;
next_state = state_on_idle;
end
always @ (posedge clk)
begin
// Clock-synchronized state change feed-back loop.
// No reset is implemented yet.
state <= next_state;
end
// Button press/release & led on/off flip FSM.
always @ (state or button)
case (state)
state_on_idle:
// LED is on, button was untouched.
// If the button is pressed now, switch to next state
// to wait for release.
begin
led_sig = 1'b1;
next_state = button ? state_on_push : state_on_idle;
end
state_on_push:
// LED is on, button was pressed.
// If the button is release now, switch to next state
// that will turn off the LED and go IDLE with LEDs off.
begin
led_sig = 1'b1;
next_state = button ? state_on_push : state_on_pop;
end
state_on_pop:
begin
// LED was on, button got pressed and released.
// Switch the LED off, go into IDLE state.
led_sig = 1'b0;
next_state = state_off_idle;
end
state_off_idle:
begin
// IDLE state with LEDs off. Button was untouched.
// If button is pressed then go to the next state
// that waits for the button release in order to
// turn on LEDs.
led_sig = 1'b0;
next_state = button ? state_off_push : state_off_idle;
end
state_off_push:
begin
// LEDs are off. Button was pressed. Wait for the button
// release in order to enable LED(s).
led_sig = 1'b0;
next_state = button ? state_off_push : state_off_pop;
end
state_off_pop:
begin
// LEDs were off, button clicked. Enable LED(s) and
// go into IDLE state with high beams.
led_sig = 1'b1;
next_state = state_on_idle;
end
default:
// Some foobar state... Recover.
begin
led_sig = 1'b1;
next_state = state_on_idle;
end
endcase
assign led[0] = led_sig;
assign led[1] = ~led_sig;
assign led[2] = led_sig;
assign led[3] = ~led_sig;
endmodule
It was synthesized for the Spartan-6 LX9 FPGA. Here is the schematics:
I tested it manually on a real device and it seems to work. So today I was practicing test bench simulation and wrote the following bench:
`timescale 1ns / 1ps
module test_bench();
reg clk;
reg button;
wire [3:0] led;
led_flip_flop prog(clk, button, led);
initial begin
#20000 $finish;
end
initial
begin
clk = 0;
forever #5 clk = ~clk;
end
initial
begin
button = 0;
forever #({$random} % 11) button = ~button;
end
endmodule
Before I had a fixed delay for the button = ~button
statement and signals in simulation looked good. However, with the random delay, it seems like button press+release signals could get in between clock strobes, and so signals look like this:
Some waves that look bad to me marked red.
As I understand it, there is a problem if the signal from the button is short and is coming in between clock cycles. Of course, in the real life only Chuck Norris can manage to press and release a button fast enough to get between a 66Mhz clock raising edges.
However, that raised few questions in my head..
- If external signals are coming with higher frequency then clock frequency (or if processing of a signal takes multiple clock cycles), what are generic approaches to process such signals?
- Should the clock always be involved? For example, can I achieve the same thing without using clock at all?
- Is this what is called "crossing a clock domain"?
Or perhaps I am doing something totally wrong and silly?
Any help is appreciated. Thank you!