arbiter is the correct term. I did a design that had 4 separate ddr controllers, and 6 client modules that wanted to use them (only 2 had global access)
first thing is to have combinational muxes for the inputs to the actual ddr controller proper (this is just part of the arbiter)
here is the set of muxes for the outputs to the client module
and finally a very simple FSM for each controller that handles requests in a prioritized manner
all these are utilizing a block based approach. also you will notice there are synchronizers, each client was in a separate clock domain. CL device is at the top of the chain so it gets first priority, being the most timing critical.
This is probably more info that you wanted but there you go. You have X physical resource and you need to have a system for acknowledging requests (whether its for 8 bits, a 128bit word, or a block transfer) and then signaling completion and giving priority to some requests over the others.
Something this design lacks is pre-emption of transfers. In this case the granularity of transfers was small enough (512 bytes) that this could be overlooked. But if you all share a single RAM and you have sometihng that MUST have data NOW, you can extend the FSM to save the transfer state and hang up the client while the most important one cleans up.