Not sure where you're coming from with respect to 'serial' registers. Generally, in a CPU nowadays these will be parallel, and usually some multiple of the machine's natural word width.
As to how you implement them...
Within a CPU, the local register set will be designed for low latency and for speed. This structure is sometimes called a register file, and it may have multiple read and write ports to support fast access to multiple operands at once. It may very well be constructed from D flops or latches, and also have bypass logic for when the read and write pointers are the same to eliminate an extra cycle of latency.
Bigger memories would tend to use FPGA RAM resources rather than D flops. The FPGA libraries offer different options for implementing RAM, including block RAM or distributed RAM (that is, repurposed LUTs), or honest-to-dog registers like for register files.
These RAM types are most easily used as parameterized macros, with synthesis taking care of the rest. Your tool chain offers various ways to make the instantiation templates. In Vivado for example, you can create the RAM as a GUI block design, then instance that in your code using the generated VHDL template for it. If you're relatively new to HDL coding this is an easy way to go.