As a small side note: whilst developing a CPLD (and then FPGA) LCDcontroller, I had a hard time deciding when one could write to the external memory, opting to add blanking intervals at the end of each line and using a FIFO as a buffer for burst writes. Out of curiosity, if anyone has a verilog/VHDL LCD controller, using external SRAM, I'd be interested to see how others have done it. I was working with an old cyclone II with SDRAM. Might pick up a MACHXO2 board (£20 farnell!) and add SRAM myself, because getting the SDRAM to work was a nightmare.
There are probably many ways of doing it.
I have done a video monitor using a LCD many years ago using an ADC, 128kByte SRAM and a XC95144XL CPLD for driving a 320x240 monochrome LCD. Because CPLDs have no blockram, I clocked everything at 18.432MHz. The ADC was clocked at 18.432MHz/3=6.144MHz giving exactly 320 pixels/line. The ADC data were written directly into SRAM. In the other two clocks data were read from the SRAM and fed into a FRC/dithering block for generating 64 greyscales.
Using a SDRAM is a bit more difficult, because you need to do burst reads, otherwise it is really slow.
You typically implement a fifo buffer (32-512 bytes) for reading and a similar or maybe smaller one for writing.
When the SDRAM controller is idle, it checks if there are data in the write fifo or space for a burst read in the read fifo. When doing a burst read I typically read 16-64 bytes/words. To keep everything simple, the SDRAM is always idle with all banks precharged. Every read/write operation starts with activating a bank followed by the actual read/write burst operation and then precharging the bank again. It may not be the most efficient way, but many SDRAM controllers found in microcontrollers work this way (many of them are really inefficient, because the bursts are rather short, therefore the overhead for activating+precharging the bank is rather high, wasting a lot of memory bandwith). When everything works you can add some more advanced features like checking pending operations if they are in the same row and skip the precharge+activate operations.
For writing operations I implemented a fifo holding both data + address for each written value. This enabled random, asynchronous writes from an external microcontroller.
If you have everything working upto this point, implementing a display controller is simple.
I implemented a freerunning timing controller generating all the sync signals. Because of the fifo at the output of the SDRAM controller it can even run in different clock domain.
At the end of each frame, the timing controller generates a reset signal, stopping the SDRAM controller from reading further data and it also flushs any remaining data in the fifo and resets the read address counter. At the last line of the vertical blanking, this reset signal is disabled and the SDRAM controller starts filling the read fifo again.
This may not be the best way of doing it, but it worked fine for me.
Synchronising the image data and the timing seems to be rather difficult to implement. That's why many display controllers use odd ways of specifying the blanking intervals and sync pulses (By reading the datasheet I couldn't figure out how to set the sync timing correctly for the PIC24FJxxxDA206, I had to look at the microchip graphics library and still don't understand completely how they do it).
Because I implemented my own SDRAM controller, it took me a very long time to get it running. It partially worked, but there were many errors in the data. I searched for timing errors, but everything was fine. The problem was timing related, but it wasn't any setup/hold timing related problem, but SDRAMs need a 100us pause after power up. My pause was too short, therefore the SDRAM did not understand the load mode register command and stayed at the default settings. Therefore the CAS latency my controller used was different from the CAS latency the SDRAM used.