...when you're trying to deal with oddball stuff.
Like clock domain crossings.
The problem at hand isn't exactly a domain crossing; the two clocks are derived from a common source... but apparently there's enough timing uncertainty between them to give the timing analyzer heartburn.
I generally try to stick to behavioral, rather than structural, code as far as possible, because it ought to be architecture-independent. (Of course, I have to use the structural form for module instantiations, whether they're my own modules or vendor macros, but that's another matter.)
Looks like I can either construct a pair of synchronizers, or stick a totally vendor-specific macro into the high-speed domain.
Guess I'll sketch out how to build the kind of synchronizer I need in discrete logic, and then translate it into vendor primitives and combinatorial functions.
Update: After some review of Verilog techniques and a bit of poking around, I implemented what I think is the right thing, in behavioral code, nicely integrated with my other behavioral code. It compiled fine.
Then I wrote another one that does exactly the same thing only running the other way across the domain boundary. I get goofy compilation errors that seem to imply that the compiler is confused about what the code is supposed to do.
This is epically annoying. If I have to resort to structural forms, integrating with my behavioral code for the part that gets the work done will be awkward.