The notes on getting the clocking right are also very much appreciated; that's always tricky with SDRAM.
I'm curious about introducing a phase shifted clock with a PLL in order to get the rise/fall timings correct. Is that standard in other controller implementations? Is that technique something that's used in other, similar situations? It sounds like a pretty generic and simple way to solve timing issues of that nature. I guess I'm mostly wondering how you came up with that solution and if there are any alternatives? The minds of EE people intrigue me :)
This makes sense because you'd have a lot of duplicated logic when you gang multiple DRAMs together.
It allows the chip designer to make trade-offs between design complexity and performance. Modern DRAM controllers can be incredibly complex (and large!) when dealing with different kinds of traffic at the same time: prioritizing CPU traffic, which is latency sensitive, over graphics workloads, which is not.
Another, close to the metal, example is the the source-synchronous data strobe signal that travels with the data from the controller to DDR DRAM or the other way around.
Going from the controller to the DRAM, it is 90 degrees out of phase with the data, which allows the DRAM to clock in the data using the rising and falling edge of the DQS signal. It's on the controller to create this 90 degrees phase shift with a DLL or PLL.
But the other way around, from DRAM to the controller, there is a 0 degrees phase shift, once again forcing the controller to create a 90 degrees shifted signal.
This also makes is possible for the DRAM drop DLL and PLL logic in some cases.
The controller is really not very complex, so it shouldn't be a showstopper.
But if you want to get super technical later DDR standards aren't really synchronous at all. There's a huge analogue component and the input clock is only a reference to feed on board PLLs and calibrate delay lines. It's simply not possible to do a traditional synchronous design at the frequencies involved.
The first synchronous DRAM type was called SDRAM and that was followed by all of the DDR standards which still use a clock and are there synchronous in operation.
Looking at my own controller code from about 15 years ago, you need a 34 state one-hot state machine and the rest comes right out of the diagram and data sheets. Careful placement and layout (I'm talking both about within the FPGA and on the PCB) does the rest. For example, for best performance you want some of the flip-flops located right at the IOB's.
Still, it's cool that something like this is available for those who, for whatever reason, might choose not to undertake writing their own. Nice.
Looks like you used wavedrom for timing diagrams. What did you use to make the state diagrams?
It's a bit verbose, but mostly because he makes everything parametrized so you can easily customize it for different targets.
There are only two things I don't like: he is calling some registers latches and he is mixing std_logic_vector and unsigned in the interface.
Edit: Mostly people just use whatever software the FPGA vendor provides. So for Xilinx you use Vivado. For Intel/Altera people use Quartus. Some people do development in an IDE like Sigasi (which I've heard is much better than the vendor specific IDE's, but I've never used it), but they still build with the vendor tooling.
As an enthusiast, that's what I use too.. also on my home Linux system. The tooling is generic enough that you can actually instrument a build system with Makefiles and the Vivado command line programs. If you have the right FPGA board you can also instrument the bitstream upload as well.
I do most of my development like any other programming language and never have to touch the custom GUIs.