I tried to be concise, but still this turned out to be quite a wall of text. The first paragraph can be skipped, it only provides information about my background
.
I'm a computer engineer with a computer science background (basically, I don't know too much about electrical engineering: I'm trying to learn that on my own, but I'm struggling). Last year, I took a class where we had to work on the plasma softcore processor. This was my first encounter with FPGAs, and while I have to admit is was no 'love at first sight', I ended up buying a cheap FPGA (the
mimas v2, which I can definitely recommend for people who want to experiment with FPGAs), downloaded Xilinx Webpack ISE, and started to do some really basic stuff. I first started messing around with the clock and VGA port, and I was able to generate a 640x480 VGA signal, and display a 128x128 picture using block RAM pretty easily. Ideally, I would want to have a fullscreen frame buffer so that I can output more interesting things (and in the end for higher resolutions too, but hey, baby steps!). Since there is not enough block RAM for a fullscreen buffer (and I would like memory with enough bandwidth to support at least one read/write port for a processor, and one read port to read the screen data), I started looking at the RAM module on the board (a Micron MT46H32M16LF or a Winbond W949D6CBHX6E, which seems to be a clone). I tried to use Xilinx MIG to generate an easier interface to access memory, but the interface that was generated had even more input signals than the RAM module. So, I downloaded the datasheets (
Micron and
Winbond), some examples (
1,
2,
3,
4), and started learning about SDRAM and DDR controllers.
My goal is to make a minimal working DDR controller, (both to learn and for fun). After some trial (but mainly error*), I discovered this stackoverflow question that suggests you should use a functional model. I finally found one on the micron site (I use mobile_ddr.v, and manually edit it to include the right parameters, which involved mainly deleting ifdef-blocks, and ocasionally changing a parameter definition that deviates from the parameters in the datasheet), and now I'm at the point where I use that to design an LPDDR controller. It helped me to get the initialization right (at least, it doesn't throw errors so I assume it's correct). However, I still have some problems:
1. The functional model spews out A LOT of setup/hold violation warnings
2. Even when I don't use a preamble, and do not raise the data strobe after a first write command, I don't get any error or warning (while the datasheet suggests this should be done within 1.25 of a clock cycle ADDITIONAL INFO HERE).
I can think of two things that relate to the first problem. The first is that I use a normal simulation (not a post-map or a post-PAR one). Now, all signals change instantly, so of couse, hold time constraints are not satisfied. In Xilinx ISE, I have a process 'generate post-PAR simulation model', but I can' find an option to actually RUN a post-PAR simulation. This document from Xilinx suggests you need Modelsim for this (which seems weird to me: why would they ship their own simulator and then recommend people to use a product from another company? But I think their decision to not support windows 10 while Microsoft is basically forcing everybody to use it is a slap in the face of their users, and also hard to rationalize).
The second thing is that the LPDDR module needs a differential clock. A heavily simplified schematic view of the important signals:
(where the DDR controller changes the control signals on the rising edge of the clock)
I'm not sure if the buffer can lead to a problematic additional delay. If the controller changes its output signals faster than the buffer (I think this is referred to as a 'race condition'?) I think it is possible that the LPDDR module would miss commands. The controller logic should be complex enough to take longer than the buffer, but I would rather have a hard guarantee.
I'm really confused about the second problem (the functional model doesn't give a warning or error when I do not raise the data strobe after a write command). In the readme from the functional model, the only thing listed under 'limitations' is "". This piece of code looks like it tests for edges in dqs:
// dqs edge checking
always @ (posedge Sys_clk) begin
// if (Write_pipeline[2] || Write_pipeline[1] || Data_in_enable) begin
if (Write_pipeline[-1]) begin
for (i=0; i<DQS_BITS; i=i+1) begin
if (expect_neg_dqs[i]) begin
$display ("%m: At time %t ERROR: Negative DQS[%1d] transition required.", $realtime, i);
end
expect_neg_dqs[i] = 1'b1;
end
end else begin
expect_neg_dqs = 0;
expect_pos_dqs = 0;
end
end
[[and here something similar for positive edges]]
So this both suggests that the functional model should test for edges in the data strobe signal. At the same time, there is no parameter for DQSS (defined as "Write command to 1st DQS latching
transition" in p51 of the winbond datasheet, and on p26 of the micron datasheet) or for the preamble.