Introduction
In an FPGA, every I/O port has its own small area on the logic fabric. This area, which is called an IOB (Input / Output Block), contains everything that is needed to support this I/O port's features: Analog circuits that ensure the correct voltages and currents on the I/O pin, as well as a few special logic elements.
I should point out that the term "IOB" belongs to the terminology used by AMD (formerly Xilinx). Each FPGA vendor uses a different term.
There are almost always IOB registers inside an IOB. These registers are flip-flops that are connected directly to the I/O port's pin.
Some flip-flops are intended for use when the pin is an input port: These flip-flops' D input is connected to the I/O port's pin. Hence a flip-flop of this sort performs sampling of the signal that arrives from the outer world.
Other flip-flops are dedicated to the pin as an output port. These flip-flops' Q output is connected to the pin.
The structure of the IOBs vary from one FPGA to the other. Some IOBs are complex and rich with features, and other IOBs have a simpler structure. Quite often, the IOB register is part of a larger logic element, e.g. a SERDES. So even if no flip-flops are explicitly depicted in the documentation's drawing that describes the IOB, it's still possible that the FPGA's I/O pins have IOB registers.
Why use IOB registers
The main motivation for using IOB registers is timing: Because of these registers' vicinity to the I/O port's pin, the clock-to-output that is achieved this way is unbeatable. Also for input ports, an IOB register has the best chances to achieve the required timing.
But even when it's easy to meet the timing requirements, there is a good reason to insist on IOB registers: Repeatability. Otherwise, the delay between the I/O port's pin and the flip-flop is different for each implementation of the FPGA project. This is because the tools are allowed to put the flip-flop in a different location each time. They are also allowed to change the routing delay as well, as long as the timing constraints are achieved. This is not a problem as long as the PCB design is correct and the interface with the external components is properly planned. However, when such problems do exist, the difference in the delay from one implementation to the next can cause confusion: Something doesn't work, you fix something in the design, and then the problem seems to be solved. But what really made the difference was a slight change in the I/O timing somewhere.
The use of IOB registers ensure that the electrical interface with the external components doesn't change unintentionally during the development process of the FPGA's logic. This makes it easier to isolate problems, when such occur.
Requesting IOB registers
It may be required to explicitly tell the FPGA tools to use IOB registers. The synthesizer is often responsible for doing this, so a synthesis attribute of this sort can be used with Vivado:
(* IOB = "TRUE" *) input the_input,
It's also possible to do the same in the XDC file:
set_property IOB true [get_ports the_input]
Another option is to add a synthesis attribute to the register that is connected to the input:
(* IOB = "TRUE" *) reg the_input_samp;
Note that an attribute in the XDC file may not be enough: Often, the synthesizer is required to replicate registers in order to put flip-flops in the IOB. This is relevant when the output of the flip-flop is also used by regular logic in the FPGA. The reason is that the output of the flip-flop that is inside the IOB can only be used for the port. Another flip-flop is hence required to produce the same output, so it can be used in the logic fabric. A synthesis attribute (as shown above) is often required in this situation.
With Quartus, commands of this sort can be added to the QSF file:
set_instance_assignment -name FAST_INPUT_REGISTER ON -to the_input set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to the_output
Each tool has a slightly different way to achieve this.
Timing constraints
Is there any reason to write timing constraints for a port that uses an IOB register? After all, there is only one possible position for the IOB register. Isn't it safe to conclude that the timing will always be the same, with or without timing constraints?
So there are primarily two good reasons for writing timing constraints even when IOB registers are used.
The first reason is to ensure that an IOB register is used: Sometimes, a change in the logic design can unintentionally prevent the use of IOBs for all or some ports. The tools rarely complain when this occurs. Rather, a flip-flop that isn't inside the IOB is silently used. A timing constraint can prevent this situation: If the timing constraint can only be achieved when all related flip-flops are inside their IOBs, the eviction of these flip-flops will not be silent: The timing constraint will fail as a result.
The second reason is that the tools may insert an intentional delay between the I/O port's pin and the IOB register (even though not all FPGAs support this feature). The purpose of this delay is to improve the timing in relation to thold (see this example with Quartus). This undesired manipulation can be prevented with a timing constraint that is achievable only without this extra delay.
set_max_delay is usually the suitable timing constraint for ensuring a consistent use of IOB registers. If the FPGA tools support the "datapath_only" option with this command (or a similar feature), it's even more convenient.
Conclusion
IOB registers should be used whenever possible. The FPGA tools may not volunteer to do this, so it may require a small effort to achieve this goal. The reward for this effort is not only optimal timing, but also with a repeatable behavior of the I/O ports.