So I have this simulating again, as far as I can tell... (see 'gowin-v-altera').
Before I start checking it back in synthesis, quick question on coding style. I could generate (for example) the clock using:
for (x=0; x<DDR3_NUM_CK; x = x + 1)
begin : DDR_Clocks
wire gowin_clock;
wire gowin_ck_oe;
ODDR gowin_ck_ddr_inst_p
(
.Q0(DDR3_CK_p[x]), // Send +ve clock to this pin
.Q1(gowin_ck_oe), // Not used but save a warning
.D0(1'b0), // clock goes low to start
.D1(1'b1), // clock goes high in 2nd phase
.TX(1'b0), // TX=0 -> Output pin
.CLK(DDR_CLK) // DDR clock
);
assign DDR3_CK_n[x] = ~DDR3_CK_p[x];
end
but you've been stressing how important it is to have the outputs perfectly aligned through the same path-types. Is the above ok, even though there might be an extra logic-delay for the negation in the DDR3_CK_n[] path ? Or would it be better to duplicate the ODDRs, something like:
for (x=0; x<DDR3_NUM_CK; x = x + 1)
begin : DDR_Clocks
wire gowin_clock;
wire gowin_ck_oe_p;
wire gowin_ck_oe_n;
ODDR gowin_ck_ddr_inst_p
(
.Q0(DDR3_CK_p[x]), // Send +ve clock to this pin
.Q1(gowin_ck_oe_p), // Not used but save a warning
.D0(1'b0), // clock goes low to start
.D1(1'b1), // clock goes high in 2nd phase
.TX(1'b0), // TX=0 -> Output pin
.CLK(DDR_CLK) // DDR clock
);
ODDR gowin_ck_ddr_inst_n
(
.Q0(DDR3_CK_n[x]), // Send -ve clock to this pin
.Q1(gowin_ck_oe_n), // Not used but save a warning
.D0(1'b1), // clock goes high to start
.D1(1'b0), // clock goes low in 2nd phase
.TX(1'b0), // TX=0 -> Output pin
.CLK(DDR_CLK) // DDR clock
);
end
Same thing applies for DQS and DQ of course.