--- Quote Start ---
Run "report_timing -setup -detail full_path..." on the failing path/domain. I find it really important to understanding timing, since it shows you exactly how a path is being analyzed. You might want to start with the Waveform tab, which gives the high-level details(clock edges, data path, clock path, etc.). It's much easier to visualize. The Data Path tab gives the same information but in much more detail, like what logic cells and interconnect delays make up the data path.
Note that there are three things in the timing report from your .sdc, the launch edge time, the latch edge time(these come from the clocks you've created) which make the setup relationship, and the iExt delay, which comes directly from your -max 25000.
What you're going to find is that your setup relationship(latch edge - launch edge) is small, I'm guessing 20ns, and your external delay is 25000ns, so your external delay chews up ALL of your margin plus another 25980ns.
Why is this? If I were to take a guess, PS2_DAT drives a register clocked by CLOCK_50. So your set_input_delay constraints say there is an external register clocked by PS2_CLK driving into port PS2_DAT. So there is path from this external register clocked by PS2_CLK to an internal one clocked by CLOCK_50. The default setup relationship of this will be 20ns, yet the max external delay is 25000, so it's impossible to meet timing.
If this is the case, you can:
a) Change the code so that PS2_DAT doesn't drive a register in the CLOCK_50 domain.
b) Cut timing on that specific path:
set_falst_path -from [get_ports PS2_DAT] -to [get_keepers {name_of_the_reg_or_registers_in_CLOCK_50_domain*}]
c) Cut timing between the two clocks:
set_clock_groups -asynchronous
-group {CLOCK_50}
-group {PS2_CLK}
d) You could also multicycle it, but I don't think that's appropriate, as I'm guessing these clocks don't have any relationship. Let me know how that goes.
--- Quote End ---
Guau, thank you very much. You nailed it!
Yes, the relationship was 20 ns. And yes, PS2_DAT drives a register in the CLOCK_50 domain. The code of the pressed key is captured in the CLOCK_50 domain once it has been decode by the module in the PS2_DAT domain (there are really two modules, one for decoding the key pressed and another one which lights some led depending on which key has been pressed)
I forgot to say that I tried to set up a multicycle of 2 (thinking that it would indicate that CLOCK_50 should capture in the second edge of PS2_CLK, although now that I write it I don't think that it makes much sense).
I tried to cut the timing as you said between the clocks and indeed that was the solution! I really don't know why I didn't do it at first. Maybe it is not yet clear to me when I should separate two clock domains.
Again, thank you very much for your answer, really. Now I see which was the problem and the solution to it.