My serial receiver verilog implementation does not act as expected
FPGA code works in behavioral simulation but not in hardware

This happens sometimes. So maybe something is wrong with the hardware, and maybe the simulation doesn't accurately model what happens in reality. Have to check both.

I assume you're a student, since there is free ready-made code that already implements serial UARTs, so my answer is about how to approach debugging this kind of problem.

1. Did synthesis really succeed? 

When you build the project, are there any diagnostic or warning messages? Does the synthesized code make sense?

Examine the post-translation/post-synthesis code that is generated by the various synthesis tools. 

As written, the code you posted is behavioral (always @posedge), not structural (instances and wires). That makes it very straightforward to simulate, but the synthesis tool has to try to recognize what you're asking for by matching against templates. If your always statement doesn't match one of the templates, then the synthesis tool won't know how to implement it. That should generate a diagnostic message somewhere.

The first translation phase generates RTL code (Register Transfer Logic) which is generic combinational logic plus flip-flops. In this example, you should expect to see some flip-flops for the baud rate counter and the state machine, and some combinational logic to determine next state. Later synthesis phases figure out how to configure the FPGA to implement that RTL code. These mapping and place-and-route phases choose which slice (Xilinx) or configurable logic block (Altera) will be which flip-flop, which pin to use for which toplevel input/output ports, and how to connect it all together.

After translation/mapping/place-and-route, you can go back and run post-mapping or post-place-and-route simulation. This simulates the RTL code that the synthesis tool generated, not the behavioral code you started with. This simulation knows where each flip-flop is located and how many picoseconds of delay each route has, so you can see a more realistic simulation of the timing edges. (Since your clock is only 25MHz I expect there should be plenty of timing margin.)

Simulation and synthesis are very different. An always block that works fine in simulation may unexpectedly be omitted after synthesis. (I once lost half of a fairly complex system because of an "incomplete initialization ignored" warning in a low-level module, which caused Xilinx ISE 14.7 to replace one entire module with a constant 0. And all of the higher-level modules that depended on that signal, got optimized away to nothing too, since their outputs became constant. Since there was no longer any internal logic to drive my SPI output, the output pin didn't get routed. Now I've developed the habit of checking the RTL after synthesis to make sure there's no missing pieces.)

I come from a C programming background, so I constantly have to challenge myself when writing Verilog: what hardware do I want it to synthesise, then make sure I'm describing it in a way that the synthesis tool can understand.

2. What is the hardware actually doing?

Since the FPGA is doing nothing that you can directly observe, it's hard to diagnose whether the FPGA is powered up, configured with your code, and running your state machine. Modify your toplevel to bring out some diagnositc outputs:


Bring state[3:0] to four of the LEDs
Bring baud_tick signal to an LED
Add a "heartbeat" LED blinker to your toplevel (just toggle a D flip-flop at half the clk rate), to help confirm that the FPGA firmware is configured. This diagnositc is worth giving up one of the LEDs, at least for now.
Bring received_byte[0] (the first and least significant bit) to an LED
Bring received_byte[7] (the last and most significant bit) to an LED


This does mean using the eight LEDs on your board for these diagnostic signals, instead of the received_byte[7:0] parallel data out. But these lower-level signals give you more useful information to see what's going in inside your module. You can change it back after you get the bugs fixed.

I assume your FPGA board has some debounced slide switches. Now's the time to put them to work:


Use a debounced slide switch to drive reset
Use a debounced slide switch to drive Rx
Use a debounced slide switch to drive clk


Temporarily change your baud rate parameter so you get baud_tick every 7 clock cycles, so that you can manually clk-toggle through all the states without losing track of time.

Step through the state machine slowly, on real hardware. 


Check that the heartbeat LED is blinking (alternating 1/2 clk frequency)
Check that baud_tick gives one pulse at the expected rate (HINT: I think this is where you'll find the problem. What if initial baud_rate_clock value is random?)
Check that the state machine goes to the correct state out of reset. 
Check that your state machine stays in the idle state when Rx is idle. 
Check that your state machine detects the start bit.
Check that your state machine cycles through the states correctly and 
returns to idle state. 
Check that the received_byte[0] and received_byte[7] values are what you expect.


An oscilloscope is a real lifeline if you have one available, this would let you see the hardware running at full speed without needing to toggle through with debounced switches. For a more complicated design this would be an essential tool.

3. Why doesn't the simulation match reality?

Fully testing a design is a really tough problem. Especially when it's your own code. In this example, your code has inputs clk, reset, and Rx. You're already driving clk.


What happens if Rx is in the "wrong" state when exiting reset? Will the state machine recover? 
What if the transmitter is using a different baud rate (+5%, -5%, +10%, -10%, x2, x0.5) 
What if the state machine starts up in an random state, will it recover or will it get stuck? 
What if the Rx frame has the wrong stop bit value? 
What if the Rx is mark when you're expecting space? 
What if the Rx is inverted? (This is a very common error in RS232 UART systems, because the logic level to RS232 level translator typically inverts.) 


You get the idea. Coming up with all the test conditions is as hard as any other kind of design work. There will always be coverage gaps, so plan on going back and adding more tests based on what you find in checking the hardware.

One of the hardest things in both programming and in HDL design, is testing your own designs. When I write a test bench for my own code, I always worry that I haven't covered enough possible test cases. And any test case that I can think of, I've probably dealt with it in my code -- it's the tests that I didn't think of that cause gaps in test coverage. For example, what if the input signal is not synchronized with the device under test? That's very common in real hardware, but can be tricky to set up in a behavioral simulation.

Hope this is enough to get you on your way. Good luck!