A typical example would be, a processor to handle all the intricate, sequential operations required for operation (scheduling functions, analyzing I/O, implementing communication protocols, etc.), then discrete logic to encode/decode bus signals to implement internal I/O registers which connect to real-time functions: ADC/DAC, timers, controllers, etc. The discrete logic, in turn, could potentially be quite intricate, and verbose if production quantities remain small enough not to justify implementing it in an ASIC (as most PC system boards got -- compare the original IBM PC-XT motherboard to late models and clones). The reason for all the logic is usually reliability and real-time performance: with cheap processors topping out at a few MIPS, it was impossible to route tens or hundreds of signals through one, in real time.
These lessons should not go to waste today. Computation is cheap, but processors crash. Pointers get corrupted. Software is inevitably the buggiest part of the system, and suffers the worst from the Dunning-Kruger effect: Bad programmers never realize how many ways their program will fail -- it should be no wonder why software is so popular, eh? -- while good programmers are constantly aware of potential problems, and attempt to avoid them.
Today, logic is cheap, when implemented in a programmable array. But beware anything that comes back to code: it's just as possible, in firmware as in software, to make something functionally equivalent to the goal, yet which fails dramatically under various edge cases (in the simulator; in real implementation; under variation of inputs and timing; temperature and manufacturing variations; etc.).
Undoubtedly, the same is still true of old discrete designs, but the much more lengthy (and expensive) design procedure likely would've included better testing (including breadboarding and real test signals), which at least helps. There's also the problem of timer sequenced logic: something you can't synthesize from VHDL, but which both simplifies (when done right) and massively complicates (when applied carelessly) discrete logic designs. There have been many discrete designs that were un-maintainable due to their use of complex webs of timer circuits. This (besides the inability to synthesize it) is why timed logic is frowned upon today.
Tim