Merge pull request #30 from AngeloJacobo/ecp5_phy

added support for lattice ecp5 PHY, now working on orangecrab ECP5
This commit is contained in:
Angelo Jacobo 2025-04-19 14:57:57 +08:00 committed by GitHub
commit 264801fc99
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
31 changed files with 281015 additions and 364443 deletions

View File

@ -0,0 +1,55 @@
PROJ=orangecrab_ecp5_ddr3
EXTRA_VERILOG_FILES= uart_rx.v uart_tx.v clk_wiz_ecppll.v ../../rtl/ddr3_top.v ../../rtl/ddr3_controller.v ../../rtl/ecp5_phy/ddr3_phy_ecp5.v ../../rtl/ecp5_phy/iserdes_soft.v ../../rtl/ecp5_phy/oserdes_soft.v
# `r0.1` or `r0.2` or `r0.2.1`
VERSION:=r0.2.1
# `25F` or `85F`
DENSITY=85F
ifneq (,$(findstring 85,$(DENSITY)))
NEXTPNR_DENSITY:=--85k
else
NEXTPNR_DENSITY:=--25k
endif
# Add Windows and Unix support
RM = rm -rf
COPY = cp -a
PATH_SEP = /
ifeq ($(OS),Windows_NT)
# When SHELL=sh.exe and this actually exists, make will silently
# switch to using that instead of cmd.exe. Unfortunately, there's
# no way to tell which environment we're running under without either
# (1) printing out an error message, or (2) finding something that
# works everywhere.
# As a result, we force the shell to be cmd.exe, so it works both
# under cygwin and normal Windows.
SHELL = cmd.exe
COPY = copy
RM = del
PATH_SEP = \\
endif
all: ${PROJ}.dfu
dfu: ${PROJ}.dfu
dfu-util --alt 0 -D $<
%.json: %.v
yosys -p "read_verilog -D LATTICE_ECP5_PHY $< ${EXTRA_VERILOG_FILES} ; synth_ecp5 -json $@ -top ${PROJ}"
%_out.config: %.json
nextpnr-ecp5 --json $< --textcfg $@ $(NEXTPNR_DENSITY) --package CSFBGA285 --lpf ${PROJ}.pcf
%.bit: %_out.config
ecppack --compress --freq 38.8 --input $< --bit $@
%.dfu : %.bit
$(COPY) $< $@
dfu-suffix -v 1209 -p 5af0 -a $@
clean:
$(RM) -f ${PROJ}.bit ${PROJ}_out.config ${PROJ}.json ${PROJ}.dfu
.PHONY: prog clean

View File

@ -0,0 +1,61 @@
// diamond 3.7 accepts this PLL
// diamond 3.8-3.9 is untested
// diamond 3.10 or higher is likely to abort with error about unable to use feedback signal
// cause of this could be from wrong CPHASE/FPHASE parameters
module clk_wiz
(
input reset, // 0:inactive, 1:reset
input CLKI, // 48 MHz, 0 deg
output CLKOP, // 160 MHz, 0 deg
output CLKOS, // 160 MHz, 90 deg
output CLKOS2, // 40 MHz, 0 deg
output locked
);
(* FREQUENCY_PIN_CLKI="48" *)
(* FREQUENCY_PIN_CLKOP="160" *)
(* FREQUENCY_PIN_CLKOS="160" *)
(* FREQUENCY_PIN_CLKOS2="40" *)
(* ICP_CURRENT="12" *) (* LPF_RESISTOR="8" *) (* MFG_ENABLE_FILTEROPAMP="1" *) (* MFG_GMCREF_SEL="2" *)
EHXPLLL #(
.PLLRST_ENA("ENABLED"),
.INTFB_WAKE("DISABLED"),
.STDBY_ENABLE("DISABLED"),
.DPHASE_SOURCE("DISABLED"),
.OUTDIVIDER_MUXA("DIVA"),
.OUTDIVIDER_MUXB("DIVB"),
.OUTDIVIDER_MUXC("DIVC"),
.OUTDIVIDER_MUXD("DIVD"),
.CLKI_DIV(3),
.CLKOP_ENABLE("ENABLED"),
.CLKOP_DIV(4),
.CLKOP_CPHASE(2),
.CLKOP_FPHASE(0),
.CLKOS_ENABLE("ENABLED"),
.CLKOS_DIV(4),
.CLKOS_CPHASE(3),
.CLKOS_FPHASE(0),
.CLKOS2_ENABLE("ENABLED"),
.CLKOS2_DIV(16),
.CLKOS2_CPHASE(2),
.CLKOS2_FPHASE(0),
.FEEDBK_PATH("CLKOP"),
.CLKFB_DIV(10)
) pll_i (
.RST(reset),
.STDBY(1'b0),
.CLKI(CLKI),
.CLKOP(CLKOP),
.CLKOS(CLKOS),
.CLKOS2(CLKOS2),
.CLKFB(CLKOP),
.CLKINTFB(),
.PHASESEL0(1'b0),
.PHASESEL1(1'b0),
.PHASEDIR(1'b1),
.PHASESTEP(1'b1),
.PHASELOADREG(1'b1),
.PLLWAKESYNC(1'b0),
.ENCLKOP(1'b0),
.LOCK(locked)
);
endmodule

View File

@ -0,0 +1,228 @@
LOCATE COMP "i_clk" SITE "A9";
IOBUF PORT "i_clk" IO_TYPE=LVCMOS33;
FREQUENCY PORT "i_clk" 48.0 MHz;
LOCATE COMP "i_rst_n" SITE "J17";
IOBUF PORT "i_rst_n" IO_TYPE=SSTL135_I;
LOCATE COMP "ddr3_clk_p" SITE "J18";
IOBUF PORT "ddr3_clk_p" SLEWRATE=FAST;
IOBUF PORT "ddr3_clk_p" IO_TYPE=SSTL135_I;
LOCATE COMP "ddr3_clk_n" SITE "K18";
IOBUF PORT "ddr3_clk_n" SLEWRATE=FAST;
IOBUF PORT "ddr3_clk_n" IO_TYPE=SSTL135_I;
LOCATE COMP "ddr3_reset_n" SITE "L18";
IOBUF PORT "ddr3_reset_n" SLEWRATE=FAST;
IOBUF PORT "ddr3_reset_n" IO_TYPE=SSTL135_I;
LOCATE COMP "ddr3_cke" SITE "D18";
IOBUF PORT "ddr3_cke" SLEWRATE=FAST;
IOBUF PORT "ddr3_cke" IO_TYPE=SSTL135_I;
LOCATE COMP "ddr3_cs_n" SITE "A12";
IOBUF PORT "ddr3_cs_n" SLEWRATE=FAST;
IOBUF PORT "ddr3_cs_n" IO_TYPE=SSTL135_I;
LOCATE COMP "ddr3_ras_n" SITE "C12";
IOBUF PORT "ddr3_ras_n" SLEWRATE=FAST;
IOBUF PORT "ddr3_ras_n" IO_TYPE=SSTL135_I;
LOCATE COMP "ddr3_cas_n" SITE "D13";
IOBUF PORT "ddr3_cas_n" SLEWRATE=FAST;
IOBUF PORT "ddr3_cas_n" IO_TYPE=SSTL135_I;
LOCATE COMP "ddr3_we_n" SITE "B12";
IOBUF PORT "ddr3_we_n" SLEWRATE=FAST;
IOBUF PORT "ddr3_we_n" IO_TYPE=SSTL135_I;
LOCATE COMP "ddr3_addr[0]" SITE "C4";
IOBUF PORT "ddr3_addr[0]" SLEWRATE=FAST;
IOBUF PORT "ddr3_addr[0]" IO_TYPE=SSTL135_I;
LOCATE COMP "ddr3_addr[1]" SITE "D2";
IOBUF PORT "ddr3_addr[1]" SLEWRATE=FAST;
IOBUF PORT "ddr3_addr[1]" IO_TYPE=SSTL135_I;
LOCATE COMP "ddr3_addr[2]" SITE "D3";
IOBUF PORT "ddr3_addr[2]" SLEWRATE=FAST;
IOBUF PORT "ddr3_addr[2]" IO_TYPE=SSTL135_I;
LOCATE COMP "ddr3_addr[3]" SITE "A3";
IOBUF PORT "ddr3_addr[3]" SLEWRATE=FAST;
IOBUF PORT "ddr3_addr[3]" IO_TYPE=SSTL135_I;
LOCATE COMP "ddr3_addr[4]" SITE "A4";
IOBUF PORT "ddr3_addr[4]" SLEWRATE=FAST;
IOBUF PORT "ddr3_addr[4]" IO_TYPE=SSTL135_I;
LOCATE COMP "ddr3_addr[5]" SITE "D4";
IOBUF PORT "ddr3_addr[5]" SLEWRATE=FAST;
IOBUF PORT "ddr3_addr[5]" IO_TYPE=SSTL135_I;
LOCATE COMP "ddr3_addr[6]" SITE "C3";
IOBUF PORT "ddr3_addr[6]" SLEWRATE=FAST;
IOBUF PORT "ddr3_addr[6]" IO_TYPE=SSTL135_I;
LOCATE COMP "ddr3_addr[7]" SITE "B2";
IOBUF PORT "ddr3_addr[7]" SLEWRATE=FAST;
IOBUF PORT "ddr3_addr[7]" IO_TYPE=SSTL135_I;
LOCATE COMP "ddr3_addr[8]" SITE "B1";
IOBUF PORT "ddr3_addr[8]" SLEWRATE=FAST;
IOBUF PORT "ddr3_addr[8]" IO_TYPE=SSTL135_I;
LOCATE COMP "ddr3_addr[9]" SITE "D1";
IOBUF PORT "ddr3_addr[9]" SLEWRATE=FAST;
IOBUF PORT "ddr3_addr[9]" IO_TYPE=SSTL135_I;
LOCATE COMP "ddr3_addr[10]" SITE "A7";
IOBUF PORT "ddr3_addr[10]" SLEWRATE=FAST;
IOBUF PORT "ddr3_addr[10]" IO_TYPE=SSTL135_I;
LOCATE COMP "ddr3_addr[11]" SITE "C2";
IOBUF PORT "ddr3_addr[11]" SLEWRATE=FAST;
IOBUF PORT "ddr3_addr[11]" IO_TYPE=SSTL135_I;
LOCATE COMP "ddr3_addr[12]" SITE "B6";
IOBUF PORT "ddr3_addr[12]" SLEWRATE=FAST;
IOBUF PORT "ddr3_addr[12]" IO_TYPE=SSTL135_I;
LOCATE COMP "ddr3_addr[13]" SITE "C1";
IOBUF PORT "ddr3_addr[13]" SLEWRATE=FAST;
IOBUF PORT "ddr3_addr[13]" IO_TYPE=SSTL135_I;
LOCATE COMP "ddr3_addr[14]" SITE "A2";
IOBUF PORT "ddr3_addr[14]" SLEWRATE=FAST;
IOBUF PORT "ddr3_addr[14]" IO_TYPE=SSTL135_I;
LOCATE COMP "ddr3_addr[15]" SITE "C7";
IOBUF PORT "ddr3_addr[15]" SLEWRATE=FAST;
IOBUF PORT "ddr3_addr[15]" IO_TYPE=SSTL135_I;
LOCATE COMP "ddr3_ba[0]" SITE "D6";
IOBUF PORT "ddr3_ba[0]" SLEWRATE=FAST;
IOBUF PORT "ddr3_ba[0]" IO_TYPE=SSTL135_I;
LOCATE COMP "ddr3_ba[1]" SITE "B7";
IOBUF PORT "ddr3_ba[1]" SLEWRATE=FAST;
IOBUF PORT "ddr3_ba[1]" IO_TYPE=SSTL135_I;
LOCATE COMP "ddr3_ba[2]" SITE "A6";
IOBUF PORT "ddr3_ba[2]" SLEWRATE=FAST;
IOBUF PORT "ddr3_ba[2]" IO_TYPE=SSTL135_I;
LOCATE COMP "ddr3_dq[0]" SITE "C17";
IOBUF PORT "ddr3_dq[0]" SLEWRATE=FAST;
IOBUF PORT "ddr3_dq[0]" IO_TYPE=SSTL135_I;
IOBUF PORT "ddr3_dq[0]" TERMINATION=OFF;
LOCATE COMP "ddr3_dq[1]" SITE "D15";
IOBUF PORT "ddr3_dq[1]" SLEWRATE=FAST;
IOBUF PORT "ddr3_dq[1]" IO_TYPE=SSTL135_I;
IOBUF PORT "ddr3_dq[1]" TERMINATION=OFF;
LOCATE COMP "ddr3_dq[2]" SITE "B17";
IOBUF PORT "ddr3_dq[2]" SLEWRATE=FAST;
IOBUF PORT "ddr3_dq[2]" IO_TYPE=SSTL135_I;
IOBUF PORT "ddr3_dq[2]" TERMINATION=OFF;
LOCATE COMP "ddr3_dq[3]" SITE "C16";
IOBUF PORT "ddr3_dq[3]" SLEWRATE=FAST;
IOBUF PORT "ddr3_dq[3]" IO_TYPE=SSTL135_I;
IOBUF PORT "ddr3_dq[3]" TERMINATION=OFF;
LOCATE COMP "ddr3_dq[4]" SITE "A15";
IOBUF PORT "ddr3_dq[4]" SLEWRATE=FAST;
IOBUF PORT "ddr3_dq[4]" IO_TYPE=SSTL135_I;
IOBUF PORT "ddr3_dq[4]" TERMINATION=OFF;
LOCATE COMP "ddr3_dq[5]" SITE "B13";
IOBUF PORT "ddr3_dq[5]" SLEWRATE=FAST;
IOBUF PORT "ddr3_dq[5]" IO_TYPE=SSTL135_I;
IOBUF PORT "ddr3_dq[5]" TERMINATION=OFF;
LOCATE COMP "ddr3_dq[6]" SITE "A17";
IOBUF PORT "ddr3_dq[6]" SLEWRATE=FAST;
IOBUF PORT "ddr3_dq[6]" IO_TYPE=SSTL135_I;
IOBUF PORT "ddr3_dq[6]" TERMINATION=OFF;
LOCATE COMP "ddr3_dq[7]" SITE "A13";
IOBUF PORT "ddr3_dq[7]" SLEWRATE=FAST;
IOBUF PORT "ddr3_dq[7]" IO_TYPE=SSTL135_I;
IOBUF PORT "ddr3_dq[7]" TERMINATION=OFF;
LOCATE COMP "ddr3_dq[8]" SITE "F17";
IOBUF PORT "ddr3_dq[8]" SLEWRATE=FAST;
IOBUF PORT "ddr3_dq[8]" IO_TYPE=SSTL135_I;
IOBUF PORT "ddr3_dq[8]" TERMINATION=OFF;
LOCATE COMP "ddr3_dq[9]" SITE "F16";
IOBUF PORT "ddr3_dq[9]" SLEWRATE=FAST;
IOBUF PORT "ddr3_dq[9]" IO_TYPE=SSTL135_I;
IOBUF PORT "ddr3_dq[9]" TERMINATION=OFF;
LOCATE COMP "ddr3_dq[10]" SITE "G15";
IOBUF PORT "ddr3_dq[10]" SLEWRATE=FAST;
IOBUF PORT "ddr3_dq[10]" IO_TYPE=SSTL135_I;
IOBUF PORT "ddr3_dq[10]" TERMINATION=OFF;
LOCATE COMP "ddr3_dq[11]" SITE "F15";
IOBUF PORT "ddr3_dq[11]" SLEWRATE=FAST;
IOBUF PORT "ddr3_dq[11]" IO_TYPE=SSTL135_I;
IOBUF PORT "ddr3_dq[11]" TERMINATION=OFF;
LOCATE COMP "ddr3_dq[12]" SITE "J16";
IOBUF PORT "ddr3_dq[12]" SLEWRATE=FAST;
IOBUF PORT "ddr3_dq[12]" IO_TYPE=SSTL135_I;
IOBUF PORT "ddr3_dq[12]" TERMINATION=OFF;
LOCATE COMP "ddr3_dq[13]" SITE "C18";
IOBUF PORT "ddr3_dq[13]" SLEWRATE=FAST;
IOBUF PORT "ddr3_dq[13]" IO_TYPE=SSTL135_I;
IOBUF PORT "ddr3_dq[13]" TERMINATION=OFF;
LOCATE COMP "ddr3_dq[14]" SITE "H16";
IOBUF PORT "ddr3_dq[14]" SLEWRATE=FAST;
IOBUF PORT "ddr3_dq[14]" IO_TYPE=SSTL135_I;
IOBUF PORT "ddr3_dq[14]" TERMINATION=OFF;
LOCATE COMP "ddr3_dq[15]" SITE "F18";
IOBUF PORT "ddr3_dq[15]" SLEWRATE=FAST;
IOBUF PORT "ddr3_dq[15]" IO_TYPE=SSTL135_I;
IOBUF PORT "ddr3_dq[15]" TERMINATION=OFF;
LOCATE COMP "ddr3_dqs_p[0]" SITE "B15";
IOBUF PORT "ddr3_dqs_p[0]" TERMINATION=OFF SLEWRATE=FAST IO_TYPE=SSTL135_I;
LOCATE COMP "ddr3_dqs_p[1]" SITE "G18";
IOBUF PORT "ddr3_dqs_p[1]" TERMINATION=OFF SLEWRATE=FAST IO_TYPE=SSTL135_I;
LOCATE COMP "ddr3_dqs_n[0]" SITE "A16";
IOBUF PORT "ddr3_dqs_n[0]" TERMINATION=OFF SLEWRATE=FAST IO_TYPE=SSTL135_I ;
LOCATE COMP "ddr3_dqs_n[1]" SITE "H17";
IOBUF PORT "ddr3_dqs_n[1]" TERMINATION=OFF SLEWRATE=FAST IO_TYPE=SSTL135_I ;
LOCATE COMP "ddr3_dm[0]" SITE "G16";
IOBUF PORT "ddr3_dm[0]" SLEWRATE=FAST;
IOBUF PORT "ddr3_dm[0]" IO_TYPE=SSTL135_I;
LOCATE COMP "ddr3_dm[1]" SITE "D16";
IOBUF PORT "ddr3_dm[1]" SLEWRATE=FAST;
IOBUF PORT "ddr3_dm[1]" IO_TYPE=SSTL135_I;
LOCATE COMP "ddr3_odt" SITE "C13";
IOBUF PORT "ddr3_odt" SLEWRATE=FAST;
IOBUF PORT "ddr3_odt" IO_TYPE=SSTL135_I;
LOCATE COMP "ddram_vccio[0]" SITE "K16";
IOBUF PORT "ddram_vccio[0]" SLEWRATE=FAST;
IOBUF PORT "ddram_vccio[0]" IO_TYPE=SSTL135_II;
LOCATE COMP "ddram_vccio[1]" SITE "D17";
IOBUF PORT "ddram_vccio[1]" SLEWRATE=FAST;
IOBUF PORT "ddram_vccio[1]" IO_TYPE=SSTL135_II;
LOCATE COMP "ddram_vccio[2]" SITE "K15";
IOBUF PORT "ddram_vccio[2]" SLEWRATE=FAST;
IOBUF PORT "ddram_vccio[2]" IO_TYPE=SSTL135_II;
LOCATE COMP "ddram_vccio[3]" SITE "K17";
IOBUF PORT "ddram_vccio[3]" SLEWRATE=FAST;
IOBUF PORT "ddram_vccio[3]" IO_TYPE=SSTL135_II;
LOCATE COMP "ddram_vccio[4]" SITE "B18";
IOBUF PORT "ddram_vccio[4]" SLEWRATE=FAST;
IOBUF PORT "ddram_vccio[4]" IO_TYPE=SSTL135_II;
LOCATE COMP "ddram_vccio[5]" SITE "C6";
IOBUF PORT "ddram_vccio[5]" SLEWRATE=FAST;
IOBUF PORT "ddram_vccio[5]" IO_TYPE=SSTL135_II;
LOCATE COMP "ddram_gnd[0]" SITE "L15";
IOBUF PORT "ddram_gnd[0]" SLEWRATE=FAST;
IOBUF PORT "ddram_gnd[0]" IO_TYPE=SSTL135_II;
LOCATE COMP "ddram_gnd[1]" SITE "L16";
IOBUF PORT "ddram_gnd[1]" SLEWRATE=FAST;
IOBUF PORT "ddram_gnd[1]" IO_TYPE=SSTL135_II;
LOCATE COMP "rgb_led0_r" SITE "K4";
IOBUF PORT "rgb_led0_r" IO_TYPE=LVCMOS33;
LOCATE COMP "rgb_led0_g" SITE "M3";
IOBUF PORT "rgb_led0_g" IO_TYPE=LVCMOS33;
LOCATE COMP "rgb_led0_b" SITE "J3";
IOBUF PORT "rgb_led0_b" IO_TYPE=LVCMOS33;
LOCATE COMP "rx" SITE "N17" ;
IOBUF PORT "rx" IO_TYPE=LVCMOS33 ;
IOBUF PORT "rx" PULLMODE=DOWN;
LOCATE COMP "tx" SITE "M18" ;
IOBUF PORT "tx" IO_TYPE=LVCMOS33 ;

View File

@ -0,0 +1,224 @@
////////////////////////////////////////////////////////////////////////////////
//
// Filename: orangecrab_ecp5_ddr3.v
// Project: UberDDR3 - An Open Source DDR3 Controller
//
// Purpose: Example demo of UberDDR3 for Orangecrab ECP5. Mechanism:
// - Green LEDs will light up once UberDDR3 is done calibrating (else red light)
// - if UART (9600 Baud Rate)receives small letter ASCII (a-z), this value will be written to DDR3
// - if UART receives capital letter ASCII (A-Z), the small letter equivalent will be retrieved from DDR3 by doing
// - a read request, once read data is available this will be sent to UART to be streamed out.
// THUS:
// - Sendng "abcdefg" to the UART terminal will store that small latter to DDR3
// - Then sending "ABCDEFG" to the UART terminal will return the small letter equivalent: "abcdefg"
//
// Engineer: Angelo C. Jacobo
//
////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2023-2025 Angelo Jacobo
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//
////////////////////////////////////////////////////////////////////////////////
`timescale 1ns / 1ps
module orangecrab_ecp5_ddr3 #(parameter MICRON_SIM = 0)
(
input wire i_clk, // 48MHz
input wire i_rst_n,
// DDR3 I/O Interface
output wire ddr3_clk_p, ddr3_clk_n,
output wire ddr3_reset_n,
output wire ddr3_cke, // CKE
output wire ddr3_cs_n, // chip select signal
output wire ddr3_ras_n, // RAS#
output wire ddr3_cas_n, // CAS#
output wire ddr3_we_n, // WE#
output wire[16-1:0] ddr3_addr,
output wire[3-1:0] ddr3_ba,
inout wire[16-1:0] ddr3_dq,
inout wire[2-1:0] ddr3_dqs_p, ddr3_dqs_n,
output wire[2-1:0] ddr3_dm,
output wire ddr3_odt, // on-die termination
output wire[6-1:0] ddram_vccio,
output wire[2-1:0] ddram_gnd,
// UART line
input wire rx,
output wire tx,
//Debug LEDs
output wire rgb_led0_r, rgb_led0_g, rgb_led0_b
);
// Note from https://orangecrab-fpga.github.io/orangecrab-hardware/docs/r0.2.1/:
// Virtual VCCIO and GND are connected to VCCIO and GND on the PCB.
// They should be driven HIGH and LOW respectively to reduce SSO noise on the DDR3 I/O bank.
assign ddram_vccio = 6'b111111;
assign ddram_gnd = 2'b00;
wire i_controller_clk, i_ddr3_clk, i_ddr3_clk_90;
wire m_axis_tvalid;
wire rx_empty;
wire tx_full;
wire o_wb_ack;
wire[7:0] o_wb_data;
wire[7:0] rd_data;
wire o_wb_stall;
reg i_wb_stb = 0, i_wb_we;
wire[31:0] o_debug1;
reg[7:0] i_wb_data;
reg[7:0] i_wb_addr;
// o_debug1 taps on value of state_calibrate (can be traced inside ddr3_controller module)
assign rgb_led0_r = !(o_debug1[4:0] != 23); // red light when not yet done
assign rgb_led0_g = !(o_debug1[4:0] == 23); // green light when done
assign rgb_led0_b = 1'b1; // always off
always @(posedge i_controller_clk) begin
begin
i_wb_stb <= 0;
i_wb_we <= 0;
i_wb_addr <= 0;
i_wb_data <= 0;
if(!o_wb_stall && m_axis_tvalid) begin
if(rd_data >= 97 && rd_data <= 122) begin //write to DDR3 if ASCII is small letter
i_wb_stb <= 1;
i_wb_we <= 1;
i_wb_addr <= ~rd_data ;
i_wb_data <= rd_data;
end
else if(rd_data >= 65 && rd_data <= 90) begin //read from DDR3 if ASCII is capital letter
i_wb_stb <= 1; //make request
i_wb_we <= 0; //read
i_wb_addr <= ~(rd_data + 8'd32);
end
end
end
end
wire clk_locked;
// generated from ecppll:
// ecppll -n clk_wiz --clkin_name CLKI --clkin 48 --clkout0_name CLKOP --clkout0 24 --clkout1_name CLKOS --clkout1 24 --phase1 90 --clkout2_name CLKOS2 --clkout2 6 -f clk_wiz_ecppll.v --reset
clk_wiz clk_wiz_inst
(
.reset(!i_rst_n), // 0:inactive, 1:reset
.CLKI(i_clk), // 48 MHz, 0 deg
.CLKOP(i_ddr3_clk), // 24 MHz, 0 deg
.CLKOS(i_ddr3_clk_90), // 24 MHz, 90 deg
.CLKOS2(i_controller_clk), // 6 MHz, 0 deg
.locked(clk_locked)
);
// UART TX/RXmodule from https://github.com/ben-marshall/uart
uart_tx #(
.BIT_RATE(9600),
.CLK_HZ(6_000_000),
.PAYLOAD_BITS(8),
.STOP_BITS(1)
) uart_tx_inst (
.clk(i_controller_clk), // Top level system clock input.
.resetn(i_rst_n && clk_locked && o_debug1[4:0] == 23), // Asynchronous active low reset.
.uart_txd(), // UART transmit pin.
.uart_tx_busy(), // Module busy sending previous item.
.uart_tx_en(o_wb_ack), // Send the data on uart_tx_data
.uart_tx_data(o_wb_data) // The data to be sent
);
uart_rx #(
.BIT_RATE(9600),
.CLK_HZ(6_000_000),
.PAYLOAD_BITS(8),
.STOP_BITS(1)
) uart_rx_inst (
.clk(i_controller_clk), // Top level system clock input.
.resetn(i_rst_n && clk_locked && o_debug1[4:0] == 23), // Asynchronous active low reset.
.uart_rxd(rx), // UART Recieve pin.
.uart_rx_en(o_debug1[4:0] == 23), // Recieve enable
.uart_rx_break(), // Did we get a BREAK message?
.uart_rx_valid(m_axis_tvalid), // Valid data recieved/available.
.uart_rx_data(rd_data) // The recieved data.
);
// DDR3 Controller
ddr3_top #(
.CONTROLLER_CLK_PERIOD(25_000), //ps, clock period of the controller interface
.DDR3_CLK_PERIOD(6_250), //ps, clock period of the DDR3 RAM device (must be 1/4 of the CONTROLLER_CLK_PERIOD)
.ROW_BITS(13), //width of row address
.COL_BITS(10), //width of column address
.BA_BITS(3), //width of bank address
.BYTE_LANES(2), //number of DDR3 modules to be controlled
.AUX_WIDTH(16), //width of aux line (must be >= 4)
.WB2_ADDR_BITS(32), //width of 2nd wishbone address bus
.WB2_DATA_BITS(32), //width of 2nd wishbone data bus
.MICRON_SIM(MICRON_SIM), //enable faster simulation for micron ddr3 model (shorten POWER_ON_RESET_HIGH and INITIAL_CKE_LOW)
.SECOND_WISHBONE(0), //set to 1 if 2nd wishbone is needed
.ECC_ENABLE(0), // set to 1 or 2 to add ECC (1 = Side-band ECC per burst, 2 = Side-band ECC per 8 bursts , 3 = Inline ECC )
.WB_ERROR(0), // set to 1 to support Wishbone error (asserts at ECC double bit error)
.DLL_OFF(1), // 1 = DLL off for low frequency ddr3 clock
.BIST_MODE(1) // 0 = No BIST, 1 = run through all address space ONCE , 2 = run through all address space for every test (burst w/r, random w/r, alternating r/w)
) ddr3_top
(
//clock and reset
.i_controller_clk(i_controller_clk),
.i_ddr3_clk(i_ddr3_clk), //i_controller_clk has period of CONTROLLER_CLK_PERIOD, i_ddr3_clk has period of DDR3_CLK_PERIOD
.i_ref_clk(1'b0),
.i_ddr3_clk_90(i_ddr3_clk_90),
.i_rst_n(i_rst_n && clk_locked),
// Wishbone inputs
.i_wb_cyc(1), //bus cycle active (1 = normal operation, 0 = all ongoing transaction are to be cancelled)
.i_wb_stb(i_wb_stb), //request a transfer
.i_wb_we(i_wb_we), //write-enable (1 = write, 0 = read)
.i_wb_addr(i_wb_addr), //burst-addressable {row,bank,col}
.i_wb_data(i_wb_data), //write data, for a 4:1 controller data width is 8 times the number of pins on the device
.i_wb_sel(16'hffff), //byte strobe for write (1 = write the byte)
.i_aux(i_wb_we), //for AXI-interface compatibility (given upon strobe)
// Wishbone outputs
.o_wb_stall(o_wb_stall), //1 = busy, cannot accept requests
.o_wb_ack(o_wb_ack), //1 = read/write request has completed
.o_wb_err(), //1 = Error due to ECC double bit error (fixed to 0 if WB_ERROR = 0)
.o_wb_data(o_wb_data), //read data, for a 4:1 controller data width is 8 times the number of pins on the device
.o_aux(),
// Wishbone 2 (PHY) inputs
.i_wb2_cyc(), //bus cycle active (1 = normal operation, 0 = all ongoing transaction are to be cancelled)
.i_wb2_stb(), //request a transfer
.i_wb2_we(), //write-enable (1 = write, 0 = read)
.i_wb2_addr(), //burst-addressable {row,bank,col}
.i_wb2_data(), //write data, for a 4:1 controller data width is 8 times the number of pins on the device
.i_wb2_sel(), //byte strobe for write (1 = write the byte)
// Wishbone 2 (Controller) outputs
.o_wb2_stall(), //1 = busy, cannot accept requests
.o_wb2_ack(), //1 = read/write request has completed
.o_wb2_data(), //read data, for a 4:1 controller data width is 8 times the number of pins on the device
// PHY Interface (to be added later)
// DDR3 I/O Interface
.o_ddr3_clk_p(ddr3_clk_p),
.o_ddr3_clk_n(ddr3_clk_n),
.o_ddr3_reset_n(ddr3_reset_n),
.o_ddr3_cke(ddr3_cke), // CKE
.o_ddr3_cs_n(ddr3_cs_n), // chip select signal (controls rank 1 only)
.o_ddr3_ras_n(ddr3_ras_n), // RAS#
.o_ddr3_cas_n(ddr3_cas_n), // CAS#
.o_ddr3_we_n(ddr3_we_n), // WE#
.o_ddr3_addr(ddr3_addr),
.o_ddr3_ba_addr(ddr3_ba),
.io_ddr3_dq(ddr3_dq),
.io_ddr3_dqs(ddr3_dqs_p),
.io_ddr3_dqs_n(ddr3_dqs_n),
.o_ddr3_dm(ddr3_dm),
.o_ddr3_odt(ddr3_odt), // on-die termination
.o_debug1(o_debug1),
.uart_tx(tx)
);
endmodule

View File

@ -0,0 +1,199 @@
//
// Module: uart_rx
//
// Notes:
// - UART reciever module.
//
module uart_rx #(
// Number of data bits recieved per UART packet.
parameter PAYLOAD_BITS = 8,
// Input bit rate of the UART line.
parameter BIT_RATE = 9600, // bits / sec
// Clock frequency in hertz.
parameter CLK_HZ = 50_000_000,
// Number of stop bits indicating the end of a packet.
parameter STOP_BITS = 1
)
(
input wire clk , // Top level system clock input.
input wire resetn , // Asynchronous active low reset.
input wire uart_rxd , // UART Recieve pin.
input wire uart_rx_en , // Recieve enable
output wire uart_rx_break, // Did we get a BREAK message?
output wire uart_rx_valid, // Valid data recieved and available.
output reg [PAYLOAD_BITS-1:0] uart_rx_data // The recieved data.
);
localparam BIT_P = 1_000_000_000 * 1/BIT_RATE; // nanoseconds
localparam CLK_P = 1_000_000_000 * 1/CLK_HZ; // nanoseconds
// --------------------------------------------------------------------------
// Internal parameters.
//
//
// Number of clock cycles per uart bit.
localparam CYCLES_PER_BIT = BIT_P / CLK_P;
//
// Size of the registers which store sample counts and bit durations.
localparam COUNT_REG_LEN = 1+$clog2(CYCLES_PER_BIT);
// --------------------------------------------------------------------------
// Internal registers.
//
//
// Internally latched value of the uart_rxd line. Helps break long timing
// paths from input pins into the logic.
reg rxd_reg;
reg rxd_reg_0;
//
// Storage for the recieved serial data.
reg [PAYLOAD_BITS-1:0] recieved_data;
//
// Counter for the number of cycles over a packet bit.
reg [COUNT_REG_LEN-1:0] cycle_counter;
//
// Counter for the number of recieved bits of the packet.
reg [3:0] bit_counter;
//
// Sample of the UART input line whenever we are in the middle of a bit frame.
reg bit_sample;
//
// Current and next states of the internal FSM.
reg [2:0] fsm_state;
reg [2:0] n_fsm_state;
localparam FSM_IDLE = 0;
localparam FSM_START= 1;
localparam FSM_RECV = 2;
localparam FSM_STOP = 3;
// ---------------------------------------------------------------------------
// Output assignment
//
assign uart_rx_break = uart_rx_valid && ~|recieved_data;
assign uart_rx_valid = fsm_state == FSM_STOP && n_fsm_state == FSM_IDLE;
always @(posedge clk) begin
if(!resetn) begin
uart_rx_data <= {PAYLOAD_BITS{1'b0}};
end else if (fsm_state == FSM_STOP) begin
uart_rx_data <= recieved_data;
end
end
// ---------------------------------------------------------------------------
// FSM next state selection.
//
wire next_bit = cycle_counter == CYCLES_PER_BIT ||
fsm_state == FSM_STOP &&
cycle_counter == CYCLES_PER_BIT/2;
wire payload_done = bit_counter == PAYLOAD_BITS ;
//
// Handle picking the next state.
always @(*) begin : p_n_fsm_state
case(fsm_state)
FSM_IDLE : n_fsm_state = rxd_reg ? FSM_IDLE : FSM_START;
FSM_START: n_fsm_state = next_bit ? FSM_RECV : FSM_START;
FSM_RECV : n_fsm_state = payload_done ? FSM_STOP : FSM_RECV ;
FSM_STOP : n_fsm_state = next_bit ? FSM_IDLE : FSM_STOP ;
default : n_fsm_state = FSM_IDLE;
endcase
end
// ---------------------------------------------------------------------------
// Internal register setting and re-setting.
//
//
// Handle updates to the recieved data register.
integer i = 0;
always @(posedge clk) begin : p_recieved_data
if(!resetn) begin
recieved_data <= {PAYLOAD_BITS{1'b0}};
end else if(fsm_state == FSM_IDLE ) begin
recieved_data <= {PAYLOAD_BITS{1'b0}};
end else if(fsm_state == FSM_RECV && next_bit ) begin
recieved_data[PAYLOAD_BITS-1] <= bit_sample;
for ( i = PAYLOAD_BITS-2; i >= 0; i = i - 1) begin
recieved_data[i] <= recieved_data[i+1];
end
end
end
//
// Increments the bit counter when recieving.
always @(posedge clk) begin : p_bit_counter
if(!resetn) begin
bit_counter <= 4'b0;
end else if(fsm_state != FSM_RECV) begin
bit_counter <= {COUNT_REG_LEN{1'b0}};
end else if(fsm_state == FSM_RECV && next_bit) begin
bit_counter <= bit_counter + 1'b1;
end
end
//
// Sample the recieved bit when in the middle of a bit frame.
always @(posedge clk) begin : p_bit_sample
if(!resetn) begin
bit_sample <= 1'b0;
end else if (cycle_counter == CYCLES_PER_BIT/2) begin
bit_sample <= rxd_reg;
end
end
//
// Increments the cycle counter when recieving.
always @(posedge clk) begin : p_cycle_counter
if(!resetn) begin
cycle_counter <= {COUNT_REG_LEN{1'b0}};
end else if(next_bit) begin
cycle_counter <= {COUNT_REG_LEN{1'b0}};
end else if(fsm_state == FSM_START ||
fsm_state == FSM_RECV ||
fsm_state == FSM_STOP ) begin
cycle_counter <= cycle_counter + 1'b1;
end
end
//
// Progresses the next FSM state.
always @(posedge clk) begin : p_fsm_state
if(!resetn) begin
fsm_state <= FSM_IDLE;
end else begin
fsm_state <= n_fsm_state;
end
end
//
// Responsible for updating the internal value of the rxd_reg.
always @(posedge clk) begin : p_rxd_reg
if(!resetn) begin
rxd_reg <= 1'b1;
rxd_reg_0 <= 1'b1;
end else if(uart_rx_en) begin
rxd_reg <= rxd_reg_0;
rxd_reg_0 <= uart_rxd;
end
end
endmodule

View File

@ -0,0 +1,182 @@
//
// Module: uart_tx
//
// Notes:
// - UART transmitter module.
//
module uart_tx #(
// Number of data bits recieved per UART packet.
parameter PAYLOAD_BITS = 8,
// Input bit rate of the UART line.
parameter BIT_RATE = 9600, // bits / sec
// Clock frequency in hertz.
parameter CLK_HZ = 50_000_000,
// Number of stop bits indicating the end of a packet.
parameter STOP_BITS = 1
)
(
input wire clk , // Top level system clock input.
input wire resetn , // Asynchronous active low reset.
output wire uart_txd , // UART transmit pin.
output wire uart_tx_busy, // Module busy sending previous item.
input wire uart_tx_en , // Send the data on uart_tx_data
input wire [PAYLOAD_BITS-1:0] uart_tx_data // The data to be sent
);
// ---------------------------------------------------------------------------
// External parameters.
//
localparam BIT_P = 1_000_000_000 * 1/BIT_RATE; // nanoseconds
localparam CLK_P = 1_000_000_000 * 1/CLK_HZ; // nanoseconds
// ---------------------------------------------------------------------------
// Internal parameters.
//
//
// Number of clock cycles per uart bit.
localparam CYCLES_PER_BIT = BIT_P / CLK_P;
//
// Size of the registers which store sample counts and bit durations.
localparam COUNT_REG_LEN = 1+$clog2(CYCLES_PER_BIT);
// ---------------------------------------------------------------------------
// Internal registers.
//
//
// Internally latched value of the uart_txd line. Helps break long timing
// paths from the logic to the output pins.
reg txd_reg;
//
// Storage for the serial data to be sent.
reg [PAYLOAD_BITS-1:0] data_to_send;
//
// Counter for the number of cycles over a packet bit.
reg [COUNT_REG_LEN-1:0] cycle_counter;
//
// Counter for the number of sent bits of the packet.
reg [3:0] bit_counter;
//
// Current and next states of the internal FSM.
reg [2:0] fsm_state;
reg [2:0] n_fsm_state;
localparam FSM_IDLE = 0;
localparam FSM_START= 1;
localparam FSM_SEND = 2;
localparam FSM_STOP = 3;
// ---------------------------------------------------------------------------
// FSM next state selection.
//
assign uart_tx_busy = fsm_state != FSM_IDLE;
assign uart_txd = txd_reg;
wire next_bit = cycle_counter == CYCLES_PER_BIT;
wire payload_done = bit_counter == PAYLOAD_BITS ;
wire stop_done = bit_counter == STOP_BITS && fsm_state == FSM_STOP;
//
// Handle picking the next state.
always @(*) begin : p_n_fsm_state
case(fsm_state)
FSM_IDLE : n_fsm_state = uart_tx_en ? FSM_START: FSM_IDLE ;
FSM_START: n_fsm_state = next_bit ? FSM_SEND : FSM_START;
FSM_SEND : n_fsm_state = payload_done ? FSM_STOP : FSM_SEND ;
FSM_STOP : n_fsm_state = stop_done ? FSM_IDLE : FSM_STOP ;
default : n_fsm_state = FSM_IDLE;
endcase
end
// ---------------------------------------------------------------------------
// Internal register setting and re-setting.
//
//
// Handle updates to the sent data register.
integer i = 0;
always @(posedge clk) begin : p_data_to_send
if(!resetn) begin
data_to_send <= {PAYLOAD_BITS{1'b0}};
end else if(fsm_state == FSM_IDLE && uart_tx_en) begin
data_to_send <= uart_tx_data;
end else if(fsm_state == FSM_SEND && next_bit ) begin
for ( i = PAYLOAD_BITS-2; i >= 0; i = i - 1) begin
data_to_send[i] <= data_to_send[i+1];
end
end
end
//
// Increments the bit counter each time a new bit frame is sent.
always @(posedge clk) begin : p_bit_counter
if(!resetn) begin
bit_counter <= 4'b0;
end else if(fsm_state != FSM_SEND && fsm_state != FSM_STOP) begin
bit_counter <= {COUNT_REG_LEN{1'b0}};
end else if(fsm_state == FSM_SEND && n_fsm_state == FSM_STOP) begin
bit_counter <= {COUNT_REG_LEN{1'b0}};
end else if(fsm_state == FSM_STOP&& next_bit) begin
bit_counter <= bit_counter + 1'b1;
end else if(fsm_state == FSM_SEND && next_bit) begin
bit_counter <= bit_counter + 1'b1;
end
end
//
// Increments the cycle counter when sending.
always @(posedge clk) begin : p_cycle_counter
if(!resetn) begin
cycle_counter <= {COUNT_REG_LEN{1'b0}};
end else if(next_bit) begin
cycle_counter <= {COUNT_REG_LEN{1'b0}};
end else if(fsm_state == FSM_START ||
fsm_state == FSM_SEND ||
fsm_state == FSM_STOP ) begin
cycle_counter <= cycle_counter + 1'b1;
end
end
//
// Progresses the next FSM state.
always @(posedge clk) begin : p_fsm_state
if(!resetn) begin
fsm_state <= FSM_IDLE;
end else begin
fsm_state <= n_fsm_state;
end
end
//
// Responsible for updating the internal value of the txd_reg.
always @(posedge clk) begin : p_txd_reg
if(!resetn) begin
txd_reg <= 1'b1;
end else if(fsm_state == FSM_IDLE) begin
txd_reg <= 1'b1;
end else if(fsm_state == FSM_START) begin
txd_reg <= 1'b0;
end else if(fsm_state == FSM_SEND) begin
txd_reg <= data_to_send[0];
end else if(fsm_state == FSM_STOP) begin
txd_reg <= 1'b1;
end
end
endmodule

View File

@ -81,8 +81,9 @@ module ddr3_controller #(
parameter[0:0] MICRON_SIM = 0, //enable faster simulation for micron ddr3 model (shorten POWER_ON_RESET_HIGH and INITIAL_CKE_LOW)
ODELAY_SUPPORTED = 1, //set to 1 when ODELAYE2 is supported
SECOND_WISHBONE = 0, //set to 1 if 2nd wishbone is needed
DLL_OFF = 0, // 1 = DLL off for low frequency ddr3 clock
WB_ERROR = 0, // set to 1 to support Wishbone error (asserts at ECC double bit error)
parameter[1:0] BIST_MODE = 1, // 0 = No BIST, 1 = run through all address space ONCE , 2 = run through all address space for every test (burst w/r, random w/r, alternating r/w)
parameter[1:0] BIST_MODE = 2, // 0 = No BIST, 1 = run through all address space ONCE , 2 = run through all address space for every test (burst w/r, random w/r, alternating r/w)
parameter[1:0] ECC_ENABLE = 0, // set to 1 or 2 to add ECC (1 = Side-band ECC per burst, 2 = Side-band ECC per 8 bursts , 3 = Inline ECC ) (only change when you know what you are doing)
parameter[1:0] DIC = 2'b00, //Output Driver Impedance Control (2'b00 = RZQ/6, 2'b01 = RZQ/7, RZQ = 240ohms) (only change when you know what you are doing)
parameter[2:0] RTT_NOM = 3'b011, //RTT Nominal (3'b000 = disabled, 3'b001 = RZQ/4, 3'b010 = RZQ/2 , 3'b011 = RZQ/6, RZQ = 240ohms)
@ -135,11 +136,11 @@ module ddr3_controller #(
input wire[LANES*serdes_ratio*2 - 1:0] i_phy_iserdes_dqs,
input wire[LANES*serdes_ratio*2 - 1:0] i_phy_iserdes_bitslip_reference,
input wire i_phy_idelayctrl_rdy,
output wire[cmd_len*serdes_ratio-1:0] o_phy_cmd,
output reg[cmd_len*serdes_ratio-1:0] o_phy_cmd,
output reg o_phy_dqs_tri_control, o_phy_dq_tri_control,
output wire o_phy_toggle_dqs,
output wire[wb_data_bits-1:0] o_phy_data,
output wire[wb_sel_bits-1:0] o_phy_dm,
output reg[wb_data_bits-1:0] o_phy_data,
output reg[wb_sel_bits-1:0] o_phy_dm,
output wire[4:0] o_phy_odelay_data_cntvaluein, o_phy_odelay_dqs_cntvaluein,
output wire[4:0] o_phy_idelay_data_cntvaluein,
output wire[4:0] o_phy_idelay_dqs_cntvaluein,
@ -267,8 +268,9 @@ module ddr3_controller #(
localparam tMOD = max(nCK_to_cycles(12), ps_to_cycles(15_000)); //cycles (controller) Mode Register Set command update delay
localparam tZQinit = max(nCK_to_cycles(512), ps_to_cycles(640_000));//cycles (controller) Power-up and RESET calibration time
/* verilator lint_on WIDTHEXPAND */
localparam CL_nCK = CL_generator(DDR3_CLK_PERIOD); //read latency (given in JEDEC DDR3 spec)
localparam CWL_nCK = CWL_generator(DDR3_CLK_PERIOD); //write latency (given in JEDEC DDR3 spec)
// FOr DLL_OFF< CL and CWL should both be 6. But effective CL is only 5 since read data is early by 1 nCK
localparam CL_nCK = DLL_OFF? 4'd5 : CL_generator(DDR3_CLK_PERIOD); //read latency (given in JEDEC DDR3 spec)
localparam CWL_nCK = DLL_OFF? 4'd6 : CWL_generator(DDR3_CLK_PERIOD); //write latency (given in JEDEC DDR3 spec)
localparam DELAY_MAX_VALUE = ps_to_cycles(INITIAL_CKE_LOW); //Largest possible delay needed by the reset and refresh sequence
localparam DELAY_COUNTER_WIDTH= $clog2(DELAY_MAX_VALUE); //Bitwidth needed by the maximum possible delay, this will be the delay counter width
localparam CALIBRATION_DELAY = 2; // must be >= 2
@ -335,13 +337,13 @@ module ddr3_controller #(
// READ_ACK_PIPE_WIDTH is the delay between read command issued (starting from the controller) until the data is received by the controller
//the delays included the ODELAY and OSERDES when issuing the read command
//and the IDELAY and ISERDES when receiving the data (NOTE TO SELF: ELABORATE ON WHY THOSE MAGIC NUMBERS)
localparam READ_ACK_PIPE_WIDTH = READ_DELAY + 1 + 2 + 1 + 1;
localparam READ_ACK_PIPE_WIDTH = READ_DELAY + 1 + 2 + 1 + 1 + (DLL_OFF? 2 : 0); // FOr DLL_OFF, phy has no delay thus add delay here
localparam MAX_ADDED_READ_ACK_DELAY = 16;
localparam DELAY_BEFORE_WRITE_LEVEL_FEEDBACK = STAGE2_DATA_DEPTH + ps_to_cycles(tWLO+tWLOE) + 10;
//plus 10 controller clocks for possible bus latency and the delay for receiving feedback DQ from IOBUF -> IDELAY -> ISERDES
localparam ECC_INFORMATION_BITS = (ECC_ENABLE == 2)? max_information_bits(wb_data_bits) : max_information_bits(wb_data_bits/8);
localparam SIM_ADDRESS_INCR_LOG2 = wb_addr_bits-2-7; // 2^(wb_addr_bits-2)/128
// Smaller wb_addr_bits for simulation so BIST will end faster
localparam wb_addr_bits_sim = MICRON_SIM? 8 : wb_addr_bits;
/*********************************************************************************************************************************************/
@ -371,7 +373,8 @@ module ddr3_controller #(
RANDOM_READ = 20,
ALTERNATE_WRITE_READ = 21,
FINISH_READ = 22,
DONE_CALIBRATE = 23;
DONE_CALIBRATE = 23,
ANALYZE_DATA_LOW_FREQ = 24;
localparam STORED_DQS_SIZE = 5, //must be >= 2
REPEAT_DQS_ANALYZE = 1,
@ -383,7 +386,7 @@ module ddr3_controller #(
/************************************************************* Set Mode Registers Parameters *************************************************************/
// MR2 (JEDEC DDR3 doc pg. 30)
localparam[2:0] PASR = 3'b000; //Partial Array Self-Refresh: Full Array
localparam[3:0] CWL = CWL_nCK-4'd5; //CAS write Latency
localparam[3:0] CWL = DLL_OFF? 6-4'd5 : CWL_nCK-4'd5; //CAS write Latency
localparam[0:0] ASR = 1'b1; //Auto Self-Refresh: on
localparam[0:0] SRT = 1'b0; //Self-Refresh Temperature Range:0 (If ASR = 1, SRT bit must be set to 0)
localparam[1:0] RTT_WR = 2'b00; //Dynamic ODT: off
@ -398,7 +401,7 @@ module ddr3_controller #(
localparam[18:0] MR3_MPR_DIS = {MR3_SEL, 13'b0_0000_0000_0000, !MPR_EN, MPR_LOC};
// MR1 (JEDEC DDR3 doc pg. 27)
localparam DLL_EN = 1'b0; //DLL Enable/Disable: Enabled(0)
localparam DLL_EN = DLL_OFF? 1'b0 : 1'b1; //DLL Enable/Disable: Enabled(0)
// localparam[1:0] DIC = 2'b01; //Output Driver Impedance Control (RZQ/7) (elevate this to parameter)
// localparam[2:0] RTT_NOM = 3'b001; //RTT Nominal: RZQ/4 (elevate this to parameter)
localparam[0:0] WL_EN = 1'b1; //Write Leveling Enable: Disabled
@ -413,7 +416,7 @@ module ddr3_controller #(
//MR0 (JEDEC DDR3 doc pg. 24)
localparam[1:0] BL = 2'b00; //Burst Length: 8 (Fixed)
localparam[3:0] CL = (CL_nCK-4)*2; //CAS Read Latency
localparam[3:0] CL = DLL_OFF? (6-4)*2 : (CL_nCK-4)*2; //CAS Read Latency
localparam[0:0] RBT = 1'b0; //Read Burst Type: Nibble Sequential
localparam[0:0] DLL_RST = 1'b1; //DLL Reset: Yes (this is self-clearing and must be applied after DLL enable)
localparam[2:0] WR = WRA_mode_register_value($rtoi($ceil(tWR/DDR3_CLK_PERIOD))); //Write recovery for autoprecharge (
@ -616,8 +619,8 @@ module ddr3_controller #(
reg reset_after_rank_1 = 0; // reset after calibration rank 1 to switch to rank 2
reg current_rank = 0;
// test calibration
(* mark_debug = "true" *) reg[wb_addr_bits:0] read_test_address_counter = 0, check_test_address_counter = 0; ////////////////////////////////////////////////////////
(* mark_debug = "true" *) reg[wb_addr_bits:0] write_test_address_counter = 0;
(* mark_debug = "true" *) reg[wb_addr_bits-1:0] read_test_address_counter = 0, check_test_address_counter = 0; ////////////////////////////////////////////////////////
(* mark_debug = "true" *) reg[wb_addr_bits-1:0] write_test_address_counter = 0;
(* mark_debug = "true" *) reg[31:0] correct_read_data = 0, wrong_read_data = 0;
/* verilator lint_off UNDRIVEN */
wire sb_err_o;
@ -638,10 +641,14 @@ module ddr3_controller #(
localparam UART_FSM_IDLE = 0,
UART_FSM_SEND_BYTE = 1,
UART_FSM_WAIT_SEND = 2,
WAIT_UART = 24;
WAIT_UART = 31;
reg[3:0] track_report = 0;
reg[$clog2(DONE_CALIBRATE)-1:0] state_calibrate_next;
reg[$clog2(DONE_CALIBRATE)-1:0] state_calibrate_next, state_calibrate_last;
`endif
reg[2:0] bitslip_counter = 0;
reg[1:0] shift_read_pipe = 0;
reg[wb_data_bits-1:0] wrong_data = 0, expected_data=0;
wire[wb_data_bits-1:0] correct_data;
// initial block for all regs
initial begin
o_wb_stall = 1;
@ -1007,7 +1014,7 @@ module ddr3_controller #(
stage2_col <= stage1_col;
stage2_bank <= stage1_bank;
stage2_row <= stage1_row;
if(ODELAY_SUPPORTED) begin
if(ODELAY_SUPPORTED || DLL_OFF) begin
stage2_data_unaligned <= stage1_data_mux;
stage2_dm_unaligned <= ~stage1_dm; //inverse each bit (1 must mean "masked" or not written)
end
@ -1052,7 +1059,7 @@ module ddr3_controller #(
end
// store parity code for stage1_data
stage2_encoded_parity <= encoded_parity;
if(ODELAY_SUPPORTED) begin
if(ODELAY_SUPPORTED || DLL_OFF) begin
stage2_data_unaligned <= stage1_data_mux;
stage2_dm_unaligned <= ecc_stage1_stall? ~stage2_ecc_write_data_mask_d : ~stage1_dm; //inverse each bit (1 must mean "masked" or not written)
end
@ -1064,7 +1071,7 @@ module ddr3_controller #(
//stage2_data -> shiftreg(CWL) -> OSERDES(DDR) -> ODELAY -> RAM
end
if(!ODELAY_SUPPORTED) begin
if(!ODELAY_SUPPORTED && !DLL_OFF) begin
stage2_data_unaligned <= stage2_data_unaligned_temp; //_temp is for added delay of 1 clock cycle (no ODELAY so no added delay)
stage2_dm_unaligned <= stage2_dm_unaligned_temp; //_temp is for added delay of 1 clock cycle (no ODELAY so no added delay)
end
@ -1234,7 +1241,7 @@ module ddr3_controller #(
// if DQ is too late (298cd0ad51c1XXXX is written) then we want to DQ to be early
// Thus, we will forward the stage2_data_unaligned directly to stage2_data[1] (instead of the usual stage2_data[0])
// checks if the DQ for this lane is late (index being zero while write_dq_late high means we will try 2nd assumption), if yes then we forward stage2_data_unaligned directly to stage2_data[1]
if(lane_write_dq_late[index] && (data_start_index[index] != 0)) begin
if((lane_write_dq_late[index] && (data_start_index[index] != 0)) && (STAGE2_DATA_DEPTH > 1)) begin
{unaligned_data[index], {
stage2_data[1][((DQ_BITS*LANES)*7 + 8*index) +: 8], stage2_data[1][((DQ_BITS*LANES)*6 + 8*index) +: 8],
stage2_data[1][((DQ_BITS*LANES)*5 + 8*index) +: 8], stage2_data[1][((DQ_BITS*LANES)*4 + 8*index) +: 8],
@ -1467,11 +1474,23 @@ module ddr3_controller #(
end
end
endgenerate
assign o_phy_data = stage2_data[STAGE2_DATA_DEPTH-1]; // the data sent to PHY is the last stage of of stage 2 (since stage 2 can have multiple pipelined stages inside it_
//assign o_phy_data = initial_calibration_done? {stage2_data[STAGE2_DATA_DEPTH-1][wb_data_bits - 1:1], 1'b0} : stage2_data[STAGE2_DATA_DEPTH-1]; // ECC test
assign o_phy_dm = stage2_dm[STAGE2_DATA_DEPTH-1];
generate
// If DLL off, add 1 more cycle of delay since PHY is faster for DLL OFF
if(DLL_OFF) begin : dll_off_out_phy
always @(posedge i_controller_clk) begin
o_phy_data <= stage2_data[STAGE2_DATA_DEPTH-1]; // the data sent to PHY is the last stage of of stage 2 (since stage 2 can have multiple pipelined stages inside it_
o_phy_dm <= stage2_dm[STAGE2_DATA_DEPTH-1];
o_phy_cmd <= {cmd_d[3], cmd_d[2], cmd_d[1], cmd_d[0]};
end
end
else begin : dll_on_out_phy
always @* begin
o_phy_data = stage2_data[STAGE2_DATA_DEPTH-1]; // the data sent to PHY is the last stage of of stage 2 (since stage 2 can have multiple pipelined stages inside it_
o_phy_dm = stage2_dm[STAGE2_DATA_DEPTH-1];
o_phy_cmd = {cmd_d[3], cmd_d[2], cmd_d[1], cmd_d[0]};
end
end
endgenerate
// DIAGRAM FOR ALL RELEVANT TIMING PARAMETERS:
//
@ -1699,7 +1718,9 @@ module ddr3_controller #(
delay_before_write_counter_d[index] = READ_TO_WRITE_DELAY + 1; // NOTE TO SELF: why plus 1?
end
// don't acknowledge if ECC request
shift_reg_read_pipe_d[READ_ACK_PIPE_WIDTH-1] = {stage2_aux, !ecc_req_stage2}; // ack is sent to shift_reg which will be shifted until the wb ack output
// higher shift_read_pipe means the earlier it will check data received from i_phy_iserdes_data
// shift_read_pipe is only used in calibration when DLL_OFF
shift_reg_read_pipe_d[READ_ACK_PIPE_WIDTH - 1 - {30'd0,shift_read_pipe}] = {stage2_aux, !ecc_req_stage2}; // ack is sent to shift_reg which will be shifted until the wb ack output
write_ack_index_d = READ_ACK_PIPE_WIDTH[$clog2(READ_ACK_PIPE_WIDTH)-1:0]-1'b1; // next index for write is the last index of shift_reg_read_pipe_d
//issue read command
if(DUAL_RANK_DIMM[0]) begin
@ -1926,7 +1947,7 @@ module ddr3_controller #(
end
end
end //end of always block
assign o_phy_cmd = {cmd_d[3], cmd_d[2], cmd_d[1], cmd_d[0]};
// register previous value of cmd_ck_en
always @(posedge i_controller_clk) begin
@ -1969,7 +1990,7 @@ module ddr3_controller #(
end
end
else begin
if(ODELAY_SUPPORTED) begin
if(ODELAY_SUPPORTED || DLL_OFF) begin
write_dqs_val[0] <= write_dqs_d || write_dqs_q[0];
end
else begin
@ -2240,6 +2261,8 @@ module ddr3_controller #(
reset_after_rank_1 <= 1'b0;
lane_write_dq_late <= 0;
lane_read_dq_early <= 0;
shift_read_pipe <= 0;
bitslip_counter <= 0;
`ifdef UART_DEBUG
uart_start_send <= 0;
uart_text <= 0;
@ -2313,23 +2336,26 @@ module ddr3_controller #(
// FSM
case(state_calibrate)
IDLE: if(i_phy_idelayctrl_rdy && instruction_address == 13) begin //we are now inside instruction 15 with maximum delay
state_calibrate <= BITSLIP_DQS_TRAIN_1;
state_calibrate <= DLL_OFF? ISSUE_WRITE_1 : BITSLIP_DQS_TRAIN_1; // If DLL Off then dont do any calibration, go straight to write-read
lane <= 0;
o_phy_odelay_data_ld <= {LANES{1'b1}};
o_phy_odelay_dqs_ld <= {LANES{1'b1}};
o_phy_idelay_data_ld <= {LANES{1'b1}};
o_phy_idelay_dqs_ld <= {LANES{1'b1}};
pause_counter <= 1; //pause instruction address @13 until read calibration finishes
pause_counter <= DLL_OFF? 0 : 1; // If DLL on, do calibration so pause instruction address @13 until read calibration finishes
write_calib_dqs <= 0;
write_calib_odt <= 0;
o_phy_write_leveling_calib <= 0;
initial_calibration_done <= 1'b0;
final_calibration_done <= 1'b0;
shift_read_pipe <= 0;
write_test_address_counter <= 0;
read_test_address_counter <= 0;
`ifdef UART_DEBUG_READ_LEVEL
uart_start_send <= 1'b1;
uart_text <= {"state=IDLE",8'h0a};
state_calibrate <= WAIT_UART;
state_calibrate_next <= BITSLIP_DQS_TRAIN_1;
state_calibrate_next <= DLL_OFF? ISSUE_WRITE_1 : BITSLIP_DQS_TRAIN_1;
`endif
end
else if(instruction_address == 13) begin
@ -2668,6 +2694,12 @@ module ddr3_controller #(
calib_data <= { {LANES{8'h80}}, {LANES{8'hdb}}, {LANES{8'hcf}}, {LANES{8'hd2}}, {LANES{8'h75}}, {LANES{8'hf1}}, {LANES{8'h2c}}, {LANES{8'h3d}} };
// write to address 1 is also a burst of 8 writes, where all lanes has same data written: 128'h80dbcfd275f12c3d
state_calibrate <= ISSUE_READ;
`ifdef UART_DEBUG_ALIGN // add this so that read is far from write (making sure i_phy_iserdes_data does not mistake the read back from write data)
uart_start_send <= 1'b1;
uart_text <= {"DONE WRITE 2", 8'h0a,8'h0a,8'h0a,8'h0a};
state_calibrate <= WAIT_UART;
state_calibrate_next <= ISSUE_READ;
`endif
end
// NOTE: WHY THERE ARE TWO ISSUE_WRITE
// address 0 and 1 is written with a deterministic data, if the DQ trace has long delay (relative to command line) then the data will be delayed
@ -2684,18 +2716,11 @@ module ddr3_controller #(
state_calibrate <= READ_DATA;
end
// ISSUE_READ_2: begin
// calib_stb <= 1;//actual request flag
// calib_aux <= 1; //AUX ID to determine later if ACK is for read or write
// calib_we <= 0; //write-enable
// calib_addr <= 1;
// state_calibrate <= READ_DATA;
// end
READ_DATA: if({o_aux[AUX_WIDTH-((ECC_ENABLE == 3)? 6 : 1) : 0], o_wb_ack_uncalibrated}== {{(AUX_WIDTH-((ECC_ENABLE == 3)? 6 : 1)){1'b0}}, 1'b1, 1'b1}) begin //wait for the read ack (which has AUX ID of 1}
read_data_store <= o_wb_data_uncalibrated; // read data on address 0
calib_stb <= 0;
state_calibrate <= ANALYZE_DATA;
state_calibrate <= DLL_OFF? ANALYZE_DATA_LOW_FREQ : ANALYZE_DATA;
// data_start_index[lane] <= 0; // dont set to zero since this may have been already set by previous CHECK_STARTING_DATA
// Possible Patterns (strong autocorrel stat)
//0x80dbcfd275f12c3d
@ -2703,26 +2728,103 @@ module ddr3_controller #(
//0x01b79fa4ebe2587b
//0x22ee5319a15aa382
write_pattern <= 128'h80dbcfd275f12c3d_9177298cd0ad51c1;
`ifdef UART_DEBUG_ALIGN
uart_start_send <= 1'b1;
// display o_wb_data_uncalibrated of current lane
// uart_text <= {8'h0a,8'h0a,"state=READ_DATA, read_data_store[lane]= 0x",
// hex8_to_ascii(o_wb_data_uncalibrated[((DQ_BITS*LANES)*7 + 8*lane) +: 8]), hex8_to_ascii(o_wb_data_uncalibrated[((DQ_BITS*LANES)*6 + 8*lane) +: 8]),
// hex8_to_ascii(o_wb_data_uncalibrated[((DQ_BITS*LANES)*5 + 8*lane) +: 8]), hex8_to_ascii(o_wb_data_uncalibrated[((DQ_BITS*LANES)*4 + 8*lane) +: 8]),
// hex8_to_ascii(o_wb_data_uncalibrated[((DQ_BITS*LANES)*3 + 8*lane) +: 8]), hex8_to_ascii(o_wb_data_uncalibrated[((DQ_BITS*LANES)*2 + 8*lane) +: 8]),
// hex8_to_ascii(o_wb_data_uncalibrated[((DQ_BITS*LANES)*1 + 8*lane) +: 8]), hex8_to_ascii(o_wb_data_uncalibrated[((DQ_BITS*LANES)*0 + 8*lane) +: 8]), 8'h0a};
//
// view o_wb_data_uncalibrated in raw form (view in Hex form)
uart_text <= {8'h0a,8'h0a, o_wb_data_uncalibrated,
8'h0a,8'h0a
};
state_calibrate <= WAIT_UART;
state_calibrate_next <= ANALYZE_DATA;
`endif
// `ifdef UART_DEBUG_ALIGN
// uart_start_send <= 1'b1;
// // display o_wb_data_uncalibrated of current lane
// // uart_text <= {8'h0a,8'h0a,"state=READ_DATA, read_data_store[lane]= 0x",
// // hex8_to_ascii(o_wb_data_uncalibrated[((DQ_BITS*LANES)*7 + 8*lane) +: 8]), hex8_to_ascii(o_wb_data_uncalibrated[((DQ_BITS*LANES)*6 + 8*lane) +: 8]),
// // hex8_to_ascii(o_wb_data_uncalibrated[((DQ_BITS*LANES)*5 + 8*lane) +: 8]), hex8_to_ascii(o_wb_data_uncalibrated[((DQ_BITS*LANES)*4 + 8*lane) +: 8]),
// // hex8_to_ascii(o_wb_data_uncalibrated[((DQ_BITS*LANES)*3 + 8*lane) +: 8]), hex8_to_ascii(o_wb_data_uncalibrated[((DQ_BITS*LANES)*2 + 8*lane) +: 8]),
// // hex8_to_ascii(o_wb_data_uncalibrated[((DQ_BITS*LANES)*1 + 8*lane) +: 8]), hex8_to_ascii(o_wb_data_uncalibrated[((DQ_BITS*LANES)*0 + 8*lane) +: 8]), 8'h0a};
// //
// // view o_wb_data_uncalibrated in raw form (view in Hex form)
// uart_text <= {8'h0a,8'h0a, "o_wb_data_uncalibrated=", 8'h0a, 8'h0a, o_wb_data_uncalibrated,
// 8'h0a,8'h0a
// };
// state_calibrate <= WAIT_UART;
// state_calibrate_next <= ANALYZE_DATA_LOW_FREQ;
// `endif
end
else if(!o_wb_stall_calib) begin
calib_stb <= 0;
// if(i_phy_iserdes_data != 0) begin
// `ifdef UART_DEBUG_ALIGN // check if i_phy_iserdes_data ever receives a non-zero data
// uart_start_send <= 1'b1;
// uart_text <= {"i_phy_iserdes_data != 0:",8'h0a,8'h0a,i_phy_iserdes_data, 8'h0a,8'h0a};
// state_calibrate <= WAIT_UART;
// state_calibrate_next <= READ_DATA;
// `endif
// end
end
ANALYZE_DATA_LOW_FREQ: begin // read_data_store should have the expected 9177298cd0ad51c1, if not then issue bitslip
if(write_pattern[0 +: 64] == {read_data_store[((DQ_BITS*LANES)*7 + 8*lane) +: 8], read_data_store[((DQ_BITS*LANES)*6 + 8*lane) +: 8],
read_data_store[((DQ_BITS*LANES)*5 + 8*lane) +: 8], read_data_store[((DQ_BITS*LANES)*4 + 8*lane) +: 8], read_data_store[((DQ_BITS*LANES)*3 + 8*lane) +: 8],
read_data_store[((DQ_BITS*LANES)*2 + 8*lane) +: 8],read_data_store[((DQ_BITS*LANES)*1 + 8*lane) +: 8],read_data_store[((DQ_BITS*LANES)*0 + 8*lane) +: 8] }) begin
/* verilator lint_off WIDTH */
if(lane == LANES - 1) begin
/* verilator lint_on WIDTH */
state_calibrate <= BIST_MODE == 0? FINISH_READ : BURST_WRITE; // go straight to FINISH_READ if BIST_MODE == 0
initial_calibration_done <= 1'b1;
`ifdef UART_DEBUG_ALIGN
uart_start_send <= 1'b1;
//uart_text <= {"state=ANALYZE_DATA_LOW_FREQ, Done All Lanes",8'h0a,"-----------------",8'h0a,8'h0a};
uart_text <= {8'h0a,8'h0a, "Done All Lanes, bitslip_counter=", hex_to_ascii(bitslip_counter), ", shift_read_pipe=", hex_to_ascii(shift_read_pipe),
", data_start_index=", hex8_to_ascii(data_start_index[lane]), ", lane_late=", hex_to_ascii(lane_write_dq_late[lane]), 8'h0a,8'h0a,
{read_data_store[((DQ_BITS*LANES)*7 + 8*lane) +: 8], read_data_store[((DQ_BITS*LANES)*6 + 8*lane) +: 8],
read_data_store[((DQ_BITS*LANES)*5 + 8*lane) +: 8], read_data_store[((DQ_BITS*LANES)*4 + 8*lane) +: 8], read_data_store[((DQ_BITS*LANES)*3 + 8*lane) +: 8],
read_data_store[((DQ_BITS*LANES)*2 + 8*lane) +: 8],read_data_store[((DQ_BITS*LANES)*1 + 8*lane) +: 8],read_data_store[((DQ_BITS*LANES)*0 + 8*lane) +: 8] },
8'h0a,8'h0a,8'h0a,8'h0a};
state_calibrate <= WAIT_UART;
state_calibrate_next <= BIST_MODE == 0? FINISH_READ : BURST_WRITE;
`endif
end
else begin
lane <= lane + 1;
bitslip_counter <= 0;
`ifdef UART_DEBUG_ALIGN
uart_start_send <= 1'b1;
// uart_text <= {"state=ANALYZE_DATA_LOW_FREQ, Done lane=",hex_to_ascii(lane),8'h0a,"-----------------",8'h0a};
uart_text <= {8'h0a,8'h0a, "Done lane=", hex_to_ascii(lane), ", bitslip_counter=", hex_to_ascii(bitslip_counter), ", shift_read_pipe=", hex_to_ascii(shift_read_pipe),
", data_start_index=", hex8_to_ascii(data_start_index[lane]), ", lane_late=", hex_to_ascii(lane_write_dq_late[lane]), 8'h0a,8'h0a,
{read_data_store[((DQ_BITS*LANES)*7 + 8*lane) +: 8], read_data_store[((DQ_BITS*LANES)*6 + 8*lane) +: 8],
read_data_store[((DQ_BITS*LANES)*5 + 8*lane) +: 8], read_data_store[((DQ_BITS*LANES)*4 + 8*lane) +: 8], read_data_store[((DQ_BITS*LANES)*3 + 8*lane) +: 8],
read_data_store[((DQ_BITS*LANES)*2 + 8*lane) +: 8],read_data_store[((DQ_BITS*LANES)*1 + 8*lane) +: 8],read_data_store[((DQ_BITS*LANES)*0 + 8*lane) +: 8] },
8'h0a,8'h0a,8'h0a,8'h0a};
state_calibrate <= WAIT_UART;
state_calibrate_next <= ANALYZE_DATA_LOW_FREQ;
`endif
end
end
else begin // issue bitslip then repeat write-read
o_phy_bitslip[lane] <= 1'b1;
bitslip_counter <= bitslip_counter + 1; // increment counter every bitslip
if(bitslip_counter == 7) begin // there are only 8 bitslip, once past this then we shift read pipe backwards (assumption is that we read too early)
shift_read_pipe <= shift_read_pipe + 1;
bitslip_counter <= 0;
if(shift_read_pipe == 1) begin // if shift_read_pipe at end then we increase data_start_index since problem might be write DQ too early thus we shift it later using data_start_index
shift_read_pipe <= 0;
data_start_index[lane] <= lane_write_dq_late[lane]? data_start_index[lane] - 8: data_start_index[lane] + 8;
if((data_start_index[lane] == 64) && !lane_write_dq_late[lane]) begin // if data_start_index at end then we assert data_start_index, last assumption is that we are writing DQ too late thus we move stage2_data forward to be sent out earlier
data_start_index[lane] <= 64;
lane_write_dq_late[lane] <= 1'b1;
end
end
end
state_calibrate <= ISSUE_WRITE_1;
`ifdef UART_DEBUG_ALIGN
uart_start_send <= 1'b1;
uart_text <= {8'h0a,8'h0a, "lane=", hex_to_ascii(lane), ", bitslip_counter=", hex_to_ascii(bitslip_counter), ", shift_read_pipe=", hex_to_ascii(shift_read_pipe),
", data_start_index=", hex8_to_ascii(data_start_index[lane]), ", lane_late=", hex_to_ascii(lane_write_dq_late[lane]), 8'h0a,8'h0a,
{read_data_store[((DQ_BITS*LANES)*7 + 8*lane) +: 8], read_data_store[((DQ_BITS*LANES)*6 + 8*lane) +: 8],
read_data_store[((DQ_BITS*LANES)*5 + 8*lane) +: 8], read_data_store[((DQ_BITS*LANES)*4 + 8*lane) +: 8], read_data_store[((DQ_BITS*LANES)*3 + 8*lane) +: 8],
read_data_store[((DQ_BITS*LANES)*2 + 8*lane) +: 8],read_data_store[((DQ_BITS*LANES)*1 + 8*lane) +: 8],read_data_store[((DQ_BITS*LANES)*0 + 8*lane) +: 8] },
8'h0a,8'h0a,8'h0a,8'h0a};
state_calibrate <= WAIT_UART;
state_calibrate_next <= ISSUE_WRITE_1;
`endif
end
end
// extract burst_0-to-burst_7 data for a specified lane then determine which byte in write_pattern does it starts (ASSUMPTION: the DQ is too early [3d_9177298cd0ad51]c1 is written)
// NOTE TO SELF: all "8" here assume DQ_BITS are 8? parameterize this properly
// data_start_index for a specified lane determine how many bits are off the data from the write command
@ -2874,152 +2976,155 @@ BITSLIP_DQS_TRAIN_3: if(train_delay == 0) begin //train again the ISERDES to cap
train_delay <= 3;
end
end
/* WRITE_ZERO: if(!o_wb_stall_calib) begin //write zero to all addresses before starting write-read test
calib_stb <= 1;
calib_aux <= 2;
calib_sel <= {wb_sel_bits{1'b1}};
calib_we <= 1;
calib_addr <= write_test_address_counter[wb_addr_bits-1:0];
calib_data <= 0;
write_test_address_counter <= write_test_address_counter + 1;
if(MICRON_SIM) begin
if(write_test_address_counter[wb_addr_bits-1:0] == 999 ) begin
state_calibrate <= BURST_WRITE;
calib_stb <= 0;
calib_aux <= 0;
calib_we <= 0;
write_test_address_counter <= 0;
end
end
else begin
if(write_test_address_counter[wb_addr_bits-1:0] == {(wb_addr_bits){1'b1}} ) begin
state_calibrate <= BURST_WRITE;
calib_stb <= 0;
calib_aux <= 0;
calib_we <= 0;
write_test_address_counter <= 0;
end
end
end*/
BURST_WRITE: if(!o_wb_stall_calib) begin // Test 1: Burst write (per byte write to test datamask feature), then burst read
calib_stb <= !write_test_address_counter[wb_addr_bits]; // create request only at the valid address space
calib_aux <= 2;
calib_stb <= 1'b1;
calib_aux <= 2; // write
if(TDQS == 0 && ECC_ENABLE == 0) begin //Test datamask by writing 1 byte at a time
calib_sel <= 1 << write_by_byte_counter;
calib_we <= 1;
calib_addr <= write_test_address_counter[wb_addr_bits-1:0];
calib_data <= {wb_sel_bits{8'haa}};
// calib_data[8*write_by_byte_counter +: 8] <= write_test_address_counter[7:0];
calib_addr <= write_test_address_counter;
calib_data <= {wb_sel_bits{8'haa}}; // set the rest (masked) to aa
calib_data[8*write_by_byte_counter +: 8] <= calib_data_randomized[8*write_by_byte_counter +: 8];
if(write_by_byte_counter == {$clog2(wb_sel_bits){1'b1}}) begin
write_test_address_counter <= MICRON_SIM? write_test_address_counter + (2**SIM_ADDRESS_INCR_LOG2) : write_test_address_counter + 1; // at BIST_MODE=1, this will create 128 writes
/* verilator lint_off WIDTHEXPAND */
if((write_test_address_counter[wb_addr_bits-1:0] - MICRON_SIM == { {2{BIST_MODE[1]}} , {(wb_addr_bits-2){1'b1}} }) && (MICRON_SIM? (write_test_address_counter != 0) : 1)) begin //MUST END AT ODD NUMBER
/* verilator lint_on WIDTHEXPAND */
write_test_address_counter <= write_test_address_counter + 1;
/* verilator lint_off WIDTHEXPAND */
if( (write_test_address_counter == { {2{BIST_MODE[1]}} , {(wb_addr_bits_sim-2){1'b1}} }) ) begin //MUST END AT ODD NUMBER
/* verilator lint_on WIDTHEXPAND */
if(BIST_MODE == 2) begin // mode 2 = burst write-read the WHOLE address space so always set the address counter back to zero
write_test_address_counter <= 0;
end
state_calibrate <= BURST_READ;
`ifdef UART_DEBUG_ALIGN
uart_start_send <= 1'b1;
uart_text <= {"DONE BURST WRITE (PER BYTE): BIST_MODE=",hex_to_ascii(BIST_MODE),8'h0a};
state_calibrate <= WAIT_UART;
state_calibrate_next <= BURST_READ;
`endif
end
end
write_by_byte_counter <= write_by_byte_counter + 1;
end
else begin // Straight burst to all bytes (all datamask on)
calib_sel <= {wb_sel_bits{1'b1}};
calib_we <= 1;
calib_addr <= write_test_address_counter[wb_addr_bits-1:0];
// calib_data <= {wb_sel_bits{write_test_address_counter[7:0]}};
calib_addr <= write_test_address_counter;
calib_data <= calib_data_randomized;
write_test_address_counter <= MICRON_SIM? write_test_address_counter + (2**SIM_ADDRESS_INCR_LOG2) : write_test_address_counter + 1; // at BIST_MODE=1, this will create 128 writes
/* verilator lint_off WIDTHEXPAND */
if((write_test_address_counter[wb_addr_bits-1:0] - MICRON_SIM == { {2{BIST_MODE[1]}} , {(wb_addr_bits-2){1'b1}} }) && (MICRON_SIM? (write_test_address_counter != 0) : 1)) begin //MUST END AT ODD NUMBER
/* verilator lint_on WIDTHEXPAND */
write_test_address_counter <= write_test_address_counter + 1;
/* verilator lint_off WIDTHEXPAND */
if( write_test_address_counter == { {2{BIST_MODE[1]}} , {(wb_addr_bits_sim-2){1'b1}} } ) begin //MUST END AT ODD NUMBER
/* verilator lint_on WIDTHEXPAND */
if(BIST_MODE == 2) begin // mode 2 = burst write-read the WHOLE address space so always set the address counter back to zero
write_test_address_counter <= 0;
end
state_calibrate <= BURST_READ;
`ifdef UART_DEBUG_ALIGN
uart_start_send <= 1'b1;
uart_text <= {"DONE BURST WRITE (ALL BYTES): BIST_MODE=",hex_to_ascii(BIST_MODE),8'h0a};
state_calibrate <= WAIT_UART;
state_calibrate_next <= BURST_READ;
`endif
end
end
end
BURST_READ: if(!o_wb_stall_calib) begin
calib_stb <= !read_test_address_counter[wb_addr_bits]; // create request only at the valid address space
calib_aux <= 3;
calib_stb <= 1'b1;
calib_aux <= 3; // read
calib_we <= 0;
calib_addr <= read_test_address_counter[wb_addr_bits-1:0];
read_test_address_counter <= MICRON_SIM? read_test_address_counter + (2**SIM_ADDRESS_INCR_LOG2) : read_test_address_counter + 1; // at BIST_MODE=1, this will create 128 reads
/* verilator lint_off WIDTHEXPAND */
if((read_test_address_counter - MICRON_SIM == { {2{BIST_MODE[1]}} , {(wb_addr_bits-2){1'b1}} }) && (MICRON_SIM? (read_test_address_counter != 0) : 1)) begin //MUST END AT ODD NUMBER
/* verilator lint_on WIDTHEXPAND */
calib_addr <= read_test_address_counter;
read_test_address_counter <= read_test_address_counter + 1;
/* verilator lint_off WIDTHEXPAND */
if( read_test_address_counter == { {2{BIST_MODE[1]}} , {(wb_addr_bits_sim-2){1'b1}} } ) begin //MUST END AT ODD NUMBER
/* verilator lint_on WIDTHEXPAND */
if(BIST_MODE == 2) begin // mode 2 = burst write-read the WHOLE address space so always set the address counter back to zero
read_test_address_counter <= 0;
end
state_calibrate <= RANDOM_WRITE;
`ifdef UART_DEBUG_ALIGN
uart_start_send <= 1'b1;
uart_text <= {"DONE BURST READ: BIST_MODE=",hex_to_ascii(BIST_MODE),8'h0a};
state_calibrate <= WAIT_UART;
state_calibrate_next <= RANDOM_WRITE;
`endif
end
end
RANDOM_WRITE: if(!o_wb_stall_calib) begin // Test 2: Random write (increments row address to force precharge-act-r/w) then random read
calib_stb <= !write_test_address_counter[wb_addr_bits]; // create request only at the valid address space
calib_aux <= 2;
calib_stb <= 1'b1;
calib_aux <= 2; // write
calib_sel <= {wb_sel_bits{1'b1}};
calib_we <= 1;
// swap row <-> bank,col so that an increment on write_test_address_counter would mean an increment on ROW (rather than on column or bank thus forcing PRE-ACT)
calib_addr[ (ROW_BITS + BA_BITS + COL_BITS- $clog2(serdes_ratio*2) - 1 + DUAL_RANK_DIMM) : (BA_BITS + COL_BITS- $clog2(serdes_ratio*2) + DUAL_RANK_DIMM) ]
<= write_test_address_counter[ROW_BITS-1:0]; // store row
calib_addr[(BA_BITS + COL_BITS- $clog2(serdes_ratio*2) - 1 + DUAL_RANK_DIMM) : 0]
<= write_test_address_counter[wb_addr_bits-1:ROW_BITS]; // store bank + col
// calib_data <= {wb_sel_bits{write_test_address_counter[7:0]}};
calib_data <= calib_data_randomized;
write_test_address_counter <= MICRON_SIM? write_test_address_counter + (2**SIM_ADDRESS_INCR_LOG2) : write_test_address_counter + 1; // at BIST_MODE=1, this will create 128 writes
/* verilator lint_off WIDTHEXPAND */
if((write_test_address_counter[wb_addr_bits-1:0] - MICRON_SIM == { 1'b1, BIST_MODE[1] , {(wb_addr_bits-2){1'b1}} }) && (MICRON_SIM? (write_test_address_counter != 0) : 1)) begin //MUST END AT ODD NUMBER since ALTERNATE_WRITE_READ must start at even
/* verilator lint_on WIDTHEXPAND */
write_test_address_counter <= write_test_address_counter + 1;
/* verilator lint_off WIDTHEXPAND */
if( write_test_address_counter == { 1'b1, BIST_MODE[1] , {(wb_addr_bits_sim-2){1'b1}} } ) begin //MUST END AT ODD NUMBER since ALTERNATE_WRITE_READ must start at even
/* verilator lint_on WIDTHEXPAND */
if(BIST_MODE == 2) begin // mode 2 = random write-read the WHOLE address space so always set the address counter back to zero
write_test_address_counter <= 0;
end
state_calibrate <= RANDOM_READ;
`ifdef UART_DEBUG_ALIGN
uart_start_send <= 1'b1;
uart_text <= {"DONE RANDOM WRITE: BIST_MODE=",hex_to_ascii(BIST_MODE),8'h0a};
state_calibrate <= WAIT_UART;
state_calibrate_next <= RANDOM_READ;
`endif
end
end
RANDOM_READ: if(!o_wb_stall_calib) begin
calib_stb <= !read_test_address_counter[wb_addr_bits]; // create request only at the valid address space
calib_aux <= 3;
calib_stb <= 1'b1;
calib_aux <= 3; // read
calib_we <= 0;
// swap row <-> bank,col so that an increment on write_test_address_counter would mean an increment on ROW (rather than on column or bank thus forcing PRE-ACT)
calib_addr[ (ROW_BITS + BA_BITS + COL_BITS- $clog2(serdes_ratio*2) - 1 + DUAL_RANK_DIMM) : (BA_BITS + COL_BITS- $clog2(serdes_ratio*2) + DUAL_RANK_DIMM) ]
<= read_test_address_counter[ROW_BITS-1:0]; // row
calib_addr[(BA_BITS + COL_BITS- $clog2(serdes_ratio*2) - 1 + DUAL_RANK_DIMM) : 0]
<= read_test_address_counter[wb_addr_bits-1:ROW_BITS]; // bank + col
read_test_address_counter <= MICRON_SIM? read_test_address_counter + (2**SIM_ADDRESS_INCR_LOG2) : read_test_address_counter + 1; // at BIST_MODE=1, this will create 128 reads
/* verilator lint_off WIDTHEXPAND */
if((read_test_address_counter - MICRON_SIM == { 1'b1 , BIST_MODE[1], {(wb_addr_bits-2){1'b1}} }) && (MICRON_SIM? (read_test_address_counter != 0) : 1)) begin //MUST END AT ODD NUMBER since ALTERNATE_WRITE_READ must start at even
/* verilator lint_on WIDTHEXPAND */
read_test_address_counter <= read_test_address_counter + 1;
/* verilator lint_off WIDTHEXPAND */
if( read_test_address_counter == { 1'b1 , BIST_MODE[1], {(wb_addr_bits_sim-2){1'b1}} }) begin //MUST END AT ODD NUMBER since ALTERNATE_WRITE_READ must start at even
/* verilator lint_on WIDTHEXPAND */
if(BIST_MODE == 2) begin // mode 2 = random write-read the WHOLE address space so always set the address counter back to zero
read_test_address_counter <= 0;
end
state_calibrate <= ALTERNATE_WRITE_READ;
`ifdef UART_DEBUG_ALIGN
uart_start_send <= 1'b1;
uart_text <= {"DONE RANDOM READ: BIST_MODE=",hex_to_ascii(BIST_MODE),8'h0a};
state_calibrate <= WAIT_UART;
state_calibrate_next <= ALTERNATE_WRITE_READ;
`endif
end
end
ALTERNATE_WRITE_READ: if(!o_wb_stall_calib) begin
calib_stb <= !write_test_address_counter[wb_addr_bits]; // create request only at the valid address space
calib_stb <= 1'b1;
calib_aux <= 2 + (calib_we? 1:0); //2 (write), 3 (read)
calib_sel <= {wb_sel_bits{1'b1}};
calib_we <= !calib_we; // alternating write-read
calib_addr <= write_test_address_counter[wb_addr_bits-1:0];
// calib_data <= {wb_sel_bits{write_test_address_counter[7:0]}};
calib_addr <= write_test_address_counter;
calib_data <= calib_data_randomized;
if(calib_we) begin // if current operation is write, then dont increment address since we wil read the same address next
write_test_address_counter <= MICRON_SIM? write_test_address_counter + (2**SIM_ADDRESS_INCR_LOG2) : write_test_address_counter + 1; // at BIST_MODE=1, this will create 128 writes
if(calib_we) begin // if current operation is write, then dont increment address since we will read the same address next
write_test_address_counter <= write_test_address_counter + 1;
end
/* verilator lint_off WIDTHEXPAND */
if((write_test_address_counter[wb_addr_bits-1:0] - MICRON_SIM == { 2'b11 , {(wb_addr_bits-2){1'b1}} }) && (MICRON_SIM? (write_test_address_counter != 0) : 1)) begin
if( write_test_address_counter == { 2'b11 , {(wb_addr_bits_sim-2){1'b1}} } ) begin
/* verilator lint_on WIDTHEXPAND */
train_delay <= 15;
state_calibrate <= FINISH_READ;
`ifdef UART_DEBUG_ALIGN
uart_start_send <= 1'b1;
uart_text <= {"DONE ALTERNATING WRITE-READ",8'h0a};
state_calibrate <= WAIT_UART;
state_calibrate_next <= FINISH_READ;
`endif
end
end
FINISH_READ: begin
@ -3038,6 +3143,14 @@ ALTERNATE_WRITE_READ: if(!o_wb_stall_calib) begin
state_calibrate <= DONE_CALIBRATE;
final_calibration_done <= 1'b1;
end
`ifdef UART_DEBUG_ALIGN
uart_start_send <= 1'b1;
uart_text <= {"DONE BIST_MODE=",hex_to_ascii(BIST_MODE),", correct_read_data=",
8'h0a, 8'h0a, correct_read_data, 8'h0a, 8'h0a, 8'h0a, 8'h0a
};
state_calibrate <= WAIT_UART;
state_calibrate_next <= DONE_CALIBRATE;
`endif
end
end
@ -3052,15 +3165,19 @@ ALTERNATE_WRITE_READ: if(!o_wb_stall_calib) begin
end
end
`ifdef UART_DEBUG
WAIT_UART: if(!uart_send_busy && !uart_start_send) begin // wait here until UART is finished
state_calibrate <= state_calibrate_next;
end
else if(uart_send_busy) begin // if already busy then uart_start_send can be deasserted
uart_start_send <= 0;
WAIT_UART: begin
if(!uart_send_busy && !uart_start_send) begin // wait here until UART is finished
state_calibrate <= state_calibrate_next;
end
else if(uart_send_busy) begin // if already busy then uart_start_send can be deasserted
uart_start_send <= 0;
end
if(!o_wb_stall_calib) begin // lower calib_stb only when the current request is accepted (stall low)
calib_stb <= 0;
end
end
`endif
endcase
`ifdef FORMAL_COVER
state_calibrate <= DONE_CALIBRATE;
`endif
@ -3108,6 +3225,8 @@ ALTERNATE_WRITE_READ: if(!o_wb_stall_calib) begin
3: uart_text <= {"RESET, correct_data(raw)=0x",8'h0a,8'h0a,
expected_data, 8'h0a,8'h0a
};
5: uart_text <= {"state_calibrate_last=0x",hex8_to_ascii(state_calibrate_last),8'h0a,8'h0a
};
endcase
state_calibrate <= WAIT_UART;
state_calibrate_next <= WAIT_UART;
@ -3135,7 +3254,7 @@ ALTERNATE_WRITE_READ: if(!o_wb_stall_calib) begin
case(state_uart_send)
UART_FSM_IDLE: if (uart_start_send) begin // if receive request to send via uart
state_uart_send <= UART_FSM_SEND_BYTE;
uart_text_length_index <= count_chars(uart_text)+5;
uart_text_length_index <= 100;
uart_send_busy <= 1;
uart_idle_timer <= MICRON_SIM? {5{1'b1}} : {20{1'b1}}; // set to all 1s for idle time
end
@ -3191,7 +3310,7 @@ ALTERNATE_WRITE_READ: if(!o_wb_stall_calib) begin
endfunction
uart_tx #(
.BIT_RATE(MICRON_SIM? (((1_000_000/CONTROLLER_CLK_PERIOD) * 1_000_000)/1) : 9600),
.BIT_RATE(MICRON_SIM? (((1_000_000/CONTROLLER_CLK_PERIOD) * 1_000_000)/1) : 9600), // fast UART during simulation
.CLK_HZ( (1_000_000/CONTROLLER_CLK_PERIOD) * 1_000_000),
.PAYLOAD_BITS(8),
.STOP_BITS(1)
@ -3227,16 +3346,15 @@ ALTERNATE_WRITE_READ: if(!o_wb_stall_calib) begin
// generate calib_data for BIST
// Uses different operations (XOR, addition, subtraction, bit rotation) to generate different values per byte.
// When MICRON_SIM=1, then we use the relevant bits (7:0 will be zero since during simulation the increment is a large number)
assign calib_data_randomized = {
{(wb_sel_bits/8){write_test_address_counter[(MICRON_SIM? SIM_ADDRESS_INCR_LOG2:0) +: 8] ^ 8'hA5, // Byte 7
write_test_address_counter[(MICRON_SIM? SIM_ADDRESS_INCR_LOG2:0) +: 8] | 8'h1A, // Byte 7
write_test_address_counter[(MICRON_SIM? SIM_ADDRESS_INCR_LOG2:0) +: 8] & 8'h33, // Byte 5
write_test_address_counter[(MICRON_SIM? SIM_ADDRESS_INCR_LOG2:0) +: 8] ^ 8'h5A, // Byte 4
write_test_address_counter[(MICRON_SIM? SIM_ADDRESS_INCR_LOG2:0) +: 8] & 8'h21, // Byte 3
write_test_address_counter[(MICRON_SIM? SIM_ADDRESS_INCR_LOG2:0) +: 8] | 8'hC7, // Byte 1
write_test_address_counter[(MICRON_SIM? SIM_ADDRESS_INCR_LOG2:0) +: 8] ^ 8'h7E, // Byte 1
write_test_address_counter[(MICRON_SIM? SIM_ADDRESS_INCR_LOG2:0) +: 8] ^ 8'h3C}} // Byte 0
{(wb_sel_bits/8){write_test_address_counter[0 +: 8] ^ 8'hA5, // Byte 7
write_test_address_counter[0 +: 8] | 8'h1A, // Byte 6
write_test_address_counter[0 +: 8] & 8'h33, // Byte 5
write_test_address_counter[0 +: 8] ^ 8'h5A, // Byte 4
write_test_address_counter[0 +: 8] & 8'h21, // Byte 3
write_test_address_counter[0 +: 8] | 8'hC7, // Byte 2
write_test_address_counter[0 +: 8] ^ 8'h7E, // Byte 1
write_test_address_counter[0 +: 8] ^ 8'h3C}} // Byte 0
};
generate
@ -3266,50 +3384,45 @@ ALTERNATE_WRITE_READ: if(!o_wb_stall_calib) begin
/*********************************************************************************************************************************************/
/******************************************************* Calibration Test Receiver *******************************************************/
reg[wb_data_bits-1:0] wrong_data = 0, expected_data=0;
wire[wb_data_bits-1:0] correct_data;
generate
if(ECC_ENABLE == 0 || ECC_ENABLE == 3) begin : ecc_enable_0_correct_data
// assign correct_data = {wb_sel_bits{check_test_address_counter[7:0]}};
assign correct_data = {
{(wb_sel_bits/8){check_test_address_counter[(MICRON_SIM? SIM_ADDRESS_INCR_LOG2:0) +: 8] ^ 8'hA5, // Byte 7
check_test_address_counter[(MICRON_SIM? SIM_ADDRESS_INCR_LOG2:0) +: 8] | 8'h1A, // Byte 7
check_test_address_counter[(MICRON_SIM? SIM_ADDRESS_INCR_LOG2:0) +: 8] & 8'h33, // Byte 5
check_test_address_counter[(MICRON_SIM? SIM_ADDRESS_INCR_LOG2:0) +: 8] ^ 8'h5A, // Byte 4
check_test_address_counter[(MICRON_SIM? SIM_ADDRESS_INCR_LOG2:0) +: 8] & 8'h21, // Byte 3
check_test_address_counter[(MICRON_SIM? SIM_ADDRESS_INCR_LOG2:0) +: 8] | 8'hC7, // Byte 1
check_test_address_counter[(MICRON_SIM? SIM_ADDRESS_INCR_LOG2:0) +: 8] ^ 8'h7E, // Byte 1
check_test_address_counter[(MICRON_SIM? SIM_ADDRESS_INCR_LOG2:0) +: 8] ^ 8'h3C }} // Byte 0
{(wb_sel_bits/8){check_test_address_counter[0 +: 8] ^ 8'hA5, // Byte 7
check_test_address_counter[0 +: 8] | 8'h1A, // Byte 6
check_test_address_counter[0 +: 8] & 8'h33, // Byte 5
check_test_address_counter[0 +: 8] ^ 8'h5A, // Byte 4
check_test_address_counter[0 +: 8] & 8'h21, // Byte 3
check_test_address_counter[0 +: 8] | 8'hC7, // Byte 2
check_test_address_counter[0 +: 8] ^ 8'h7E, // Byte 1
check_test_address_counter[0 +: 8] ^ 8'h3C }} // Byte 0
};
end
else if(ECC_ENABLE == 1) begin : ecc_enable_1_correct_data
wire[wb_data_bits-1:0] correct_data_orig;
// assign correct_data_orig = {wb_sel_bits{check_test_address_counter[7:0]}};
assign correct_data_orig = {
{(wb_sel_bits/8){check_test_address_counter[(MICRON_SIM? SIM_ADDRESS_INCR_LOG2:0) +: 8] ^ 8'hA5, // Byte 7
check_test_address_counter[(MICRON_SIM? SIM_ADDRESS_INCR_LOG2:0) +: 8] | 8'h1A, // Byte 7
check_test_address_counter[(MICRON_SIM? SIM_ADDRESS_INCR_LOG2:0) +: 8] & 8'h33, // Byte 5
check_test_address_counter[(MICRON_SIM? SIM_ADDRESS_INCR_LOG2:0) +: 8] ^ 8'h5A, // Byte 4
check_test_address_counter[(MICRON_SIM? SIM_ADDRESS_INCR_LOG2:0) +: 8] & 8'h21, // Byte 3
check_test_address_counter[(MICRON_SIM? SIM_ADDRESS_INCR_LOG2:0) +: 8] | 8'hC7, // Byte 1
check_test_address_counter[(MICRON_SIM? SIM_ADDRESS_INCR_LOG2:0) +: 8] ^ 8'h7E, // Byte 1
check_test_address_counter[(MICRON_SIM? SIM_ADDRESS_INCR_LOG2:0) +: 8] ^ 8'h3C}} // Byte 0
assign correct_data = {
{(wb_sel_bits/8){check_test_address_counter[0 +: 8] ^ 8'hA5, // Byte 7
check_test_address_counter[0 +: 8] | 8'h1A, // Byte 6
check_test_address_counter[0 +: 8] & 8'h33, // Byte 5
check_test_address_counter[0 +: 8] ^ 8'h5A, // Byte 4
check_test_address_counter[0 +: 8] & 8'h21, // Byte 3
check_test_address_counter[0 +: 8] | 8'hC7, // Byte 2
check_test_address_counter[0 +: 8] ^ 8'h7E, // Byte 1
check_test_address_counter[0 +: 8] ^ 8'h3C }} // Byte 0
};
assign correct_data = {{(wb_data_bits-ECC_INFORMATION_BITS*8){1'b0}} , correct_data_orig[ECC_INFORMATION_BITS*8 - 1 : 0]}; //only ECC_INFORMATION_BITS are valid in o_wb_data
end
else if(ECC_ENABLE == 2) begin : ecc_enable_2_correct_data
wire[wb_data_bits-1:0] correct_data_orig;
// assign correct_data_orig = {wb_sel_bits{check_test_address_counter[7:0]}};
assign correct_data_orig = {
{(wb_sel_bits/8){check_test_address_counter[(MICRON_SIM? SIM_ADDRESS_INCR_LOG2:0) +: 8] ^ 8'hA5, // Byte 7
check_test_address_counter[(MICRON_SIM? SIM_ADDRESS_INCR_LOG2:0) +: 8] | 8'h1A, // Byte 7
check_test_address_counter[(MICRON_SIM? SIM_ADDRESS_INCR_LOG2:0) +: 8] & 8'h33, // Byte 5
check_test_address_counter[(MICRON_SIM? SIM_ADDRESS_INCR_LOG2:0) +: 8] ^ 8'h5A, // Byte 4
check_test_address_counter[(MICRON_SIM? SIM_ADDRESS_INCR_LOG2:0) +: 8] & 8'h21, // Byte 3
check_test_address_counter[(MICRON_SIM? SIM_ADDRESS_INCR_LOG2:0) +: 8] | 8'hC7, // Byte 1
check_test_address_counter[(MICRON_SIM? SIM_ADDRESS_INCR_LOG2:0) +: 8] ^ 8'h7E, // Byte 1
check_test_address_counter[(MICRON_SIM? SIM_ADDRESS_INCR_LOG2:0) +: 8] ^ 8'h3C}} // Byte 0
assign correct_data = {
{(wb_sel_bits/8){check_test_address_counter[0 +: 8] ^ 8'hA5, // Byte 7
check_test_address_counter[0 +: 8] | 8'h1A, // Byte 6
check_test_address_counter[0 +: 8] & 8'h33, // Byte 5
check_test_address_counter[0 +: 8] ^ 8'h5A, // Byte 4
check_test_address_counter[0 +: 8] & 8'h21, // Byte 3
check_test_address_counter[0 +: 8] | 8'hC7, // Byte 2
check_test_address_counter[0 +: 8] ^ 8'h7E, // Byte 1
check_test_address_counter[0 +: 8] ^ 8'h3C }} // Byte 0
};
assign correct_data = {{(wb_data_bits-ECC_INFORMATION_BITS){1'b0}} , correct_data_orig[ECC_INFORMATION_BITS - 1 : 0]}; //only ECC_INFORMATION_BITS are valid in o_wb_data
end
@ -3318,8 +3431,8 @@ ALTERNATE_WRITE_READ: if(!o_wb_stall_calib) begin
always @(posedge i_controller_clk) begin
if(sync_rst_controller) begin
check_test_address_counter <= 0;
correct_read_data <= 0;
wrong_read_data <= 0;
// correct_read_data <= 0; // dont reset so data is preserved when forced reset after wrong data
// wrong_read_data <= 0;
reset_from_test <= 0;
end
else begin
@ -3333,10 +3446,18 @@ ALTERNATE_WRITE_READ: if(!o_wb_stall_calib) begin
wrong_read_data <= wrong_read_data + 1;
wrong_data <= o_wb_data;
expected_data <= correct_data;
reset_from_test <= !final_calibration_done; //reset controller when a wrong data is received (only when calibration is not yet done)
`ifdef UART_DEBUG
state_calibrate_last <= state_calibrate;
reset_from_test <= 1'b0; // dont reset when uart debugging
`else
reset_from_test <= !final_calibration_done; //reset controller when a wrong data is received (only when calibration is not yet done) AND UART_DEBUG is not defined
`endif
end
/* verilator lint_off WIDTHEXPAND */
check_test_address_counter <= check_test_address_counter + (MICRON_SIM? (2**SIM_ADDRESS_INCR_LOG2) : 1);
check_test_address_counter <= check_test_address_counter + 1;
if(check_test_address_counter == {(wb_addr_bits_sim){1'b1}}) begin // if last address, then jump back to zero
check_test_address_counter <= {(wb_addr_bits){1'b0}};
end
/* verilator lint_on WIDTHEXPAND */
end
end
@ -3518,14 +3639,14 @@ ALTERNATE_WRITE_READ: if(!o_wb_stall_calib) begin
end //end of if(wb2_stb)
end//end of else
end//end of always
end : use_second_wishbone
end
else begin : no_second_wishbone
always @* begin
o_wb2_stall = 1'b1; // will not accept any request
o_wb2_ack = 1'b0;
o_wb2_data = 0;
end
end : no_second_wishbone
end
endgenerate
// Logic connected to debug port

View File

@ -50,6 +50,7 @@ module ddr3_top #(
parameter[0:0] MICRON_SIM = 0, //enable faster simulation for micron ddr3 model (shorten POWER_ON_RESET_HIGH and INITIAL_CKE_LOW)
ODELAY_SUPPORTED = 0, //set to 1 when ODELAYE2 is supported
SECOND_WISHBONE = 0, //set to 1 if 2nd wishbone for debugging is needed
DLL_OFF = 0, // 1 = DLL off for low frequency ddr3 clock (< 125MHz)
WB_ERROR = 0, // set to 1 to support Wishbone error (asserts at ECC double bit error)
parameter[1:0] BIST_MODE = 1, // 0 = No BIST, 1 = run through all address space ONCE , 2 = run through all address space for every test (burst w/r, random w/r, alternating r/w)
parameter[1:0] ECC_ENABLE = 0, // set to 1 or 2 to add ECC (1 = Side-band ECC per burst, 2 = Side-band ECC per 8 bursts , 3 = Inline ECC )
@ -259,6 +260,7 @@ ddr3_top #(
.ODELAY_SUPPORTED(ODELAY_SUPPORTED), //set to 1 when ODELAYE2 is supported
.SECOND_WISHBONE(SECOND_WISHBONE), //set to 1 if 2nd wishbone is needed
.ECC_ENABLE(ECC_ENABLE), // set to 1 or 2 to add ECC (1 = Side-band ECC per burst, 2 = Side-band ECC per 8 bursts , 3 = Inline ECC )
.DLL_OFF(DLL_OFF), // 1 = DLL off for low frequency ddr3 clock (< 125MHz)
.WB_ERROR(WB_ERROR), // set to 1 to support Wishbone error (asserts at ECC double bit error)
.BIST_MODE(BIST_MODE), // 0 = No BIST, 1 = run through all address space ONCE , 2 = run through all address space for every test (burst w/r, random w/r, alternating r/w)
.DIC(DIC), //Output Driver Impedance Control (2'b00 = RZQ/6, 2'b01 = RZQ/7, RZQ = 240ohms)
@ -330,63 +332,118 @@ ddr3_top #(
.i_user_self_refresh(user_self_refresh),
.uart_tx(uart_tx)
);
ddr3_phy #(
.ROW_BITS(ROW_BITS), //width of row address
.BA_BITS(BA_BITS), //width of bank address
.DQ_BITS(DQ_BITS), //width of DQ
.LANES(BYTE_LANES), //8 lanes of DQ
.CONTROLLER_CLK_PERIOD(CONTROLLER_CLK_PERIOD), //ps, period of clock input to this DDR3 controller module
.DDR3_CLK_PERIOD(DDR3_CLK_PERIOD), //ps, period of clock input to DDR3 RAM device
.ODELAY_SUPPORTED(ODELAY_SUPPORTED), //set to 1 when ODELAYE2 is supported
.DUAL_RANK_DIMM(DUAL_RANK_DIMM) // enable dual rank DIMM (1 = enable, 0 = disable)
) ddr3_phy_inst (
.i_controller_clk(i_controller_clk),
.i_ddr3_clk(i_ddr3_clk),
.i_ref_clk(i_ref_clk),
.i_ddr3_clk_90(i_ddr3_clk_90),
.i_rst_n(i_rst_n),
// Controller Interface
.i_controller_reset(reset),
.i_controller_cmd(cmd),
.i_controller_dqs_tri_control(dqs_tri_control),
.i_controller_dq_tri_control(dq_tri_control),
.i_controller_toggle_dqs(toggle_dqs),
.i_controller_data(data),
.i_controller_dm(dm),
.i_controller_odelay_data_cntvaluein(odelay_data_cntvaluein),
.i_controller_odelay_dqs_cntvaluein(odelay_dqs_cntvaluein),
.i_controller_idelay_data_cntvaluein(idelay_data_cntvaluein),
.i_controller_idelay_dqs_cntvaluein(idelay_dqs_cntvaluein),
.i_controller_odelay_data_ld(odelay_data_ld),
.i_controller_odelay_dqs_ld(odelay_dqs_ld),
.i_controller_idelay_data_ld(idelay_data_ld),
.i_controller_idelay_dqs_ld(idelay_dqs_ld),
.i_controller_bitslip(bitslip),
.i_controller_write_leveling_calib(write_leveling_calib),
.o_controller_iserdes_data(iserdes_data),
.o_controller_iserdes_dqs(iserdes_dqs),
.o_controller_iserdes_bitslip_reference(iserdes_bitslip_reference),
.o_controller_idelayctrl_rdy(idelayctrl_rdy),
// DDR3 I/O Interface
.o_ddr3_clk_p(o_ddr3_clk_p),
.o_ddr3_clk_n(o_ddr3_clk_n),
.o_ddr3_reset_n(o_ddr3_reset_n),
.o_ddr3_cke(o_ddr3_cke), // CKE
.o_ddr3_cs_n(o_ddr3_cs_n), // chip select signal
.o_ddr3_ras_n(o_ddr3_ras_n), // RAS#
.o_ddr3_cas_n(o_ddr3_cas_n), // CAS#
.o_ddr3_we_n(o_ddr3_we_n), // WE#
.o_ddr3_addr(o_ddr3_addr),
.o_ddr3_ba_addr(o_ddr3_ba_addr),
.io_ddr3_dq(io_ddr3_dq),
.io_ddr3_dqs(io_ddr3_dqs),
.io_ddr3_dqs_n(io_ddr3_dqs_n),
.o_ddr3_dm(o_ddr3_dm),
.o_ddr3_odt(o_ddr3_odt), // on-die termination
.o_ddr3_debug_read_dqs_p(/*o_ddr3_debug_read_dqs_p*/),
.o_ddr3_debug_read_dqs_n(/*o_ddr3_debug_read_dqs_n*/)
);
`ifndef LATTICE_ECP5_PHY // XILINX PHY
ddr3_phy #(
.ROW_BITS(ROW_BITS), //width of row address
.BA_BITS(BA_BITS), //width of bank address
.DQ_BITS(DQ_BITS), //width of DQ
.LANES(BYTE_LANES), //8 lanes of DQ
.CONTROLLER_CLK_PERIOD(CONTROLLER_CLK_PERIOD), //ps, period of clock input to this DDR3 controller module
.DDR3_CLK_PERIOD(DDR3_CLK_PERIOD), //ps, period of clock input to DDR3 RAM device
.ODELAY_SUPPORTED(ODELAY_SUPPORTED), //set to 1 when ODELAYE2 is supported
.DUAL_RANK_DIMM(DUAL_RANK_DIMM) // enable dual rank DIMM (1 = enable, 0 = disable)
) ddr3_phy_inst (
.i_controller_clk(i_controller_clk),
.i_ddr3_clk(i_ddr3_clk),
.i_ref_clk(i_ref_clk),
.i_ddr3_clk_90(i_ddr3_clk_90),
.i_rst_n(i_rst_n),
// Controller Interface
.i_controller_reset(reset),
.i_controller_cmd(cmd),
.i_controller_dqs_tri_control(dqs_tri_control),
.i_controller_dq_tri_control(dq_tri_control),
.i_controller_toggle_dqs(toggle_dqs),
.i_controller_data(data),
.i_controller_dm(dm),
.i_controller_odelay_data_cntvaluein(odelay_data_cntvaluein),
.i_controller_odelay_dqs_cntvaluein(odelay_dqs_cntvaluein),
.i_controller_idelay_data_cntvaluein(idelay_data_cntvaluein),
.i_controller_idelay_dqs_cntvaluein(idelay_dqs_cntvaluein),
.i_controller_odelay_data_ld(odelay_data_ld),
.i_controller_odelay_dqs_ld(odelay_dqs_ld),
.i_controller_idelay_data_ld(idelay_data_ld),
.i_controller_idelay_dqs_ld(idelay_dqs_ld),
.i_controller_bitslip(bitslip),
.i_controller_write_leveling_calib(write_leveling_calib),
.o_controller_iserdes_data(iserdes_data),
.o_controller_iserdes_dqs(iserdes_dqs),
.o_controller_iserdes_bitslip_reference(iserdes_bitslip_reference),
.o_controller_idelayctrl_rdy(idelayctrl_rdy),
// DDR3 I/O Interface
.o_ddr3_clk_p(o_ddr3_clk_p),
.o_ddr3_clk_n(o_ddr3_clk_n),
.o_ddr3_reset_n(o_ddr3_reset_n),
.o_ddr3_cke(o_ddr3_cke), // CKE
.o_ddr3_cs_n(o_ddr3_cs_n), // chip select signal
.o_ddr3_ras_n(o_ddr3_ras_n), // RAS#
.o_ddr3_cas_n(o_ddr3_cas_n), // CAS#
.o_ddr3_we_n(o_ddr3_we_n), // WE#
.o_ddr3_addr(o_ddr3_addr),
.o_ddr3_ba_addr(o_ddr3_ba_addr),
.io_ddr3_dq(io_ddr3_dq),
.io_ddr3_dqs(io_ddr3_dqs),
.io_ddr3_dqs_n(io_ddr3_dqs_n),
.o_ddr3_dm(o_ddr3_dm),
.o_ddr3_odt(o_ddr3_odt), // on-die termination
.o_ddr3_debug_read_dqs_p(/*o_ddr3_debug_read_dqs_p*/),
.o_ddr3_debug_read_dqs_n(/*o_ddr3_debug_read_dqs_n*/)
);
`else // LATTICE ECP5 PHY
ddr3_phy_ecp5 #(
.ROW_BITS(ROW_BITS), //width of row address
.BA_BITS(BA_BITS), //width of bank address
.DQ_BITS(DQ_BITS), //width of DQ
.LANES(BYTE_LANES), //8 lanes of DQ
.CONTROLLER_CLK_PERIOD(CONTROLLER_CLK_PERIOD) //ps, period of clock input to this DDR3 controller module
) ddr3_phy_inst (
.i_controller_clk(i_controller_clk),
.i_ddr3_clk(i_ddr3_clk),
.i_ref_clk(i_ref_clk),
.i_ddr3_clk_90(i_ddr3_clk_90),
.i_rst_n(i_rst_n),
// Controller Interface
.i_controller_reset(reset),
.i_controller_cmd(cmd),
.i_controller_dqs_tri_control(dqs_tri_control),
.i_controller_dq_tri_control(dq_tri_control),
.i_controller_toggle_dqs(toggle_dqs),
.i_controller_data(data),
.i_controller_dm(dm),
.i_controller_odelay_data_cntvaluein(odelay_data_cntvaluein),
.i_controller_odelay_dqs_cntvaluein(odelay_dqs_cntvaluein),
.i_controller_idelay_data_cntvaluein(idelay_data_cntvaluein),
.i_controller_idelay_dqs_cntvaluein(idelay_dqs_cntvaluein),
.i_controller_odelay_data_ld(odelay_data_ld),
.i_controller_odelay_dqs_ld(odelay_dqs_ld),
.i_controller_idelay_data_ld(idelay_data_ld),
.i_controller_idelay_dqs_ld(idelay_dqs_ld),
.i_controller_bitslip(bitslip),
.i_controller_write_leveling_calib(write_leveling_calib),
.o_controller_iserdes_data(iserdes_data),
.o_controller_iserdes_dqs(iserdes_dqs),
.o_controller_iserdes_bitslip_reference(iserdes_bitslip_reference),
.o_controller_idelayctrl_rdy(idelayctrl_rdy),
// DDR3 I/O Interface
.o_ddr3_clk_p(o_ddr3_clk_p),
.o_ddr3_clk_n(o_ddr3_clk_n),
.o_ddr3_reset_n(o_ddr3_reset_n),
.o_ddr3_cke(o_ddr3_cke), // CKE
.o_ddr3_cs_n(o_ddr3_cs_n), // chip select signal
.o_ddr3_ras_n(o_ddr3_ras_n), // RAS#
.o_ddr3_cas_n(o_ddr3_cas_n), // CAS#
.o_ddr3_we_n(o_ddr3_we_n), // WE#
.o_ddr3_addr(o_ddr3_addr),
.o_ddr3_ba_addr(o_ddr3_ba_addr),
.io_ddr3_dq(io_ddr3_dq),
.io_ddr3_dqs(io_ddr3_dqs),
.io_ddr3_dqs_n(io_ddr3_dqs_n),
.o_ddr3_dm(o_ddr3_dm),
.o_ddr3_odt(o_ddr3_odt), // on-die termination
.o_ddr3_debug_read_dqs_p(/*o_ddr3_debug_read_dqs_p*/),
.o_ddr3_debug_read_dqs_n(/*o_ddr3_debug_read_dqs_n*/)
);
`endif
// // display value of parameters for easy debugging
// initial begin

View File

@ -0,0 +1,393 @@
////////////////////////////////////////////////////////////////////////////////
//
// Filename: ddr3_phy.v
// Project: UberDDR3 - An Open Source DDR3 Controller
//
// Purpose: PHY component for the DDR3 controller. Handles the primitives such
// as IOSERDES, IODELAY, and IOBUF. These generates the signals connected to
// the DDR3 RAM.
//
// Engineer: Angelo C. Jacobo
//
////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2023-2025 Angelo Jacobo
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//
////////////////////////////////////////////////////////////////////////////////
`default_nettype none
`timescale 1ps / 1ps
//`define DEBUG_DQS // uncomment to route the raw DQS to output port for debugging
module ddr3_phy_ecp5 #(
parameter CONTROLLER_CLK_PERIOD = 10_000, //ps, clock period of the controller interface
DDR3_CLK_PERIOD = 2_500, //ps, clock period of the DDR3 RAM device (must be 1/4 of the CONTROLLER_CLK_PERIOD)
ROW_BITS = 14, //width of row address
BA_BITS = 3,
DQ_BITS = 8,
LANES = 8,
DUAL_RANK_DIMM = 0, // enable dual rank DIMM (1 = enable, 0 = disable)
parameter[0:0] ODELAY_SUPPORTED = 1, //set to 1 when ODELAYE2 is supported
USE_IO_TERMINATION = 0, //use IOBUF_DCIEN and IOBUFDS_DCIEN when 1
NO_IOSERDES_LOOPBACK = 1, // don't use IOSERDES loopback for bitslip training
LATTICE_ECP5 = 1, // 1 = Lattice ECP PHY, 0 = Xilinx PHY
// The next parameters act more like a localparam (since user does not have to set this manually) but was added here to simplify port declaration
parameter serdes_ratio = 4, // this controller is fixed as a 4:1 memory controller (CONTROLLER_CLK_PERIOD/DDR3_CLK_PERIOD = 4)
wb_data_bits = DQ_BITS*LANES*serdes_ratio*2,
wb_sel_bits = wb_data_bits / 8,
//4 is the width of a single ddr3 command {cs_n, ras_n, cas_n, we_n} plus 3 (ck_en, odt, reset_n) plus bank bits plus row bits
cmd_len = 4 + 3 + BA_BITS + ROW_BITS + 2*DUAL_RANK_DIMM
)(
input wire i_controller_clk, i_ddr3_clk, i_ref_clk,
input wire i_ddr3_clk_90, //required only when ODELAY_SUPPORTED is zero
input wire i_rst_n,
// Controller Interface
input wire i_controller_reset,
input wire[cmd_len*serdes_ratio-1:0] i_controller_cmd,
input wire i_controller_dqs_tri_control, i_controller_dq_tri_control,
input wire i_controller_toggle_dqs,
input wire[wb_data_bits-1:0] i_controller_data,
input wire[wb_sel_bits-1:0] i_controller_dm,
input wire[4:0] i_controller_odelay_data_cntvaluein,i_controller_odelay_dqs_cntvaluein,
input wire[4:0] i_controller_idelay_data_cntvaluein,i_controller_idelay_dqs_cntvaluein,
input wire[LANES-1:0] i_controller_odelay_data_ld, i_controller_odelay_dqs_ld,
input wire[LANES-1:0] i_controller_idelay_data_ld, i_controller_idelay_dqs_ld,
input wire[LANES-1:0] i_controller_bitslip,
input wire i_controller_write_leveling_calib,
output wire[DQ_BITS*LANES*8-1:0] o_controller_iserdes_data,
output wire[LANES*8-1:0] o_controller_iserdes_dqs,
output wire[LANES*8-1:0] o_controller_iserdes_bitslip_reference,
output wire o_controller_idelayctrl_rdy,
// DDR3 I/O Interface
output wire[DUAL_RANK_DIMM:0] o_ddr3_clk_p,o_ddr3_clk_n,
output wire o_ddr3_reset_n,
output wire[DUAL_RANK_DIMM:0] o_ddr3_cke, // CKE
output wire[DUAL_RANK_DIMM:0] o_ddr3_cs_n, // chip select signal
output wire o_ddr3_ras_n, // RAS#
output wire o_ddr3_cas_n, // CAS#
output wire o_ddr3_we_n, // WE#
output wire[ROW_BITS-1:0] o_ddr3_addr,
output wire[BA_BITS-1:0] o_ddr3_ba_addr,
inout wire[(DQ_BITS*LANES)-1:0] io_ddr3_dq,
inout wire[(DQ_BITS*LANES)/8-1:0] io_ddr3_dqs, io_ddr3_dqs_n,
output wire[LANES-1:0] o_ddr3_dm,
output wire[DUAL_RANK_DIMM:0] o_ddr3_odt, // on-die termination
// DEBUG PHY
output wire[(DQ_BITS*LANES)/8-1:0] o_ddr3_debug_read_dqs_p,
output wire[(DQ_BITS*LANES)/8-1:0] o_ddr3_debug_read_dqs_n
);
// cmd bit assignment
localparam CMD_CS_N_2 = cmd_len - 1,
CMD_CS_N = DUAL_RANK_DIMM[0]? cmd_len - 2 : cmd_len - 1,
CMD_RAS_N = DUAL_RANK_DIMM[0]? cmd_len - 3 : cmd_len - 2,
CMD_CAS_N = DUAL_RANK_DIMM[0]? cmd_len - 4 : cmd_len - 3,
CMD_WE_N = DUAL_RANK_DIMM[0]? cmd_len - 5 : cmd_len - 4,
CMD_ODT = DUAL_RANK_DIMM[0]? cmd_len - 6 : cmd_len - 5,
CMD_CKE_2 = DUAL_RANK_DIMM[0]? cmd_len - 7 : cmd_len - 6,
CMD_CKE = DUAL_RANK_DIMM[0]? cmd_len - 8 : cmd_len - 6,
CMD_RESET_N = DUAL_RANK_DIMM[0]? cmd_len - 9 : cmd_len - 7,
CMD_BANK_START = BA_BITS + ROW_BITS - 1,
CMD_ADDRESS_START = ROW_BITS - 1;
localparam SYNC_RESET_DELAY = 52_000/CONTROLLER_CLK_PERIOD; //52_000 ps of reset pulse width required for IDELAYCTRL
localparam READ_DATA_DELAY = ( (DDR3_CLK_PERIOD/4)/25 > 127)? 127 : (DDR3_CLK_PERIOD/4)/25,
WRITE_DQS_DELAY = ( (DDR3_CLK_PERIOD/4)/25 > 127)? 127 : (DDR3_CLK_PERIOD/4)/25,
READ_DQS_DELAY = ( (DDR3_CLK_PERIOD/4)/25 > 127)? 127 : (DDR3_CLK_PERIOD/4)/25;
localparam DATA_IDELAY_TAP = ((DDR3_CLK_PERIOD/4))/78.125; // delay incoming data by 90 degrees of DDR3_CLK_PERIOD
genvar gen_index;
wire[cmd_len-1:0] oserdes_cmd, //serialized(4:1) i_controller_cmd_slot_x
cmd;//delayed oserdes_cmd
wire[(DQ_BITS*LANES)-1:0] oserdes_data, odelay_data, idelay_data, read_dq;
wire[LANES-1:0] oserdes_dm, odelay_dm;
wire[LANES-1:0] odelay_dqs_p, odelay_dqs_n, read_dqs, idelay_dqs;
wire[DQ_BITS*LANES-1:0] oserdes_dq_tri_control;
wire[LANES-1:0] oserdes_dqs_p, oserdes_dqs_n;
wire[LANES-1:0] oserdes_dqs_tri_control;
wire[LANES-1:0] oserdes_bitslip_reference;
reg[$clog2(SYNC_RESET_DELAY):0] delay_before_release_reset;
reg sync_rst = 0;
wire ddr3_clk;
reg toggle_dqs_q; //past value of i_controller_toggle_dqs
wire ddr3_clk_delayed;
wire idelayctrl_rdy;
wire dci_locked;
reg[LANES*8-1:0] o_controller_iserdes_bitslip_reference_reg;
reg[LANES - 1 : 0] shift_bitslip_index;
// initial value of bitslip reference
initial begin
o_controller_iserdes_bitslip_reference_reg = {LANES{8'b0001_1110}};
shift_bitslip_index = 0;
end
assign o_controller_idelayctrl_rdy = 1'b1;
`ifdef DEBUG_DQS
assign o_ddr3_debug_read_dqs_p = io_ddr3_dqs;
assign o_ddr3_debug_read_dqs_n = io_ddr3_dqs_n;
`else
assign o_ddr3_debug_read_dqs_p = 0;
assign o_ddr3_debug_read_dqs_n = 0;
`endif
//synchronous reset
always @(posedge i_controller_clk) begin
if(!i_rst_n || i_controller_reset) begin
sync_rst <= 1'b1;
delay_before_release_reset <= SYNC_RESET_DELAY[$clog2(SYNC_RESET_DELAY):0];
toggle_dqs_q <= 0;
end
else begin
delay_before_release_reset <= (delay_before_release_reset == 0)? 0: delay_before_release_reset - 1;
sync_rst <= !(delay_before_release_reset == 0);
toggle_dqs_q <= i_controller_toggle_dqs;
end
end
//PHY cmd
generate
for(gen_index = 0; gen_index < cmd_len; gen_index = gen_index + 1) begin
oserdes_soft #(.LATTICE_ECP5(LATTICE_ECP5)) oserdes_soft_cmd(
.CLK(i_ddr3_clk), // High speed clock
.CLKDIV(i_controller_clk), // Divided clock
.RST(sync_rst), // Active high reset
.D1(i_controller_cmd[cmd_len*0 + gen_index]),
.D2(i_controller_cmd[cmd_len*0 + gen_index]),
.D3(i_controller_cmd[cmd_len*1 + gen_index]),
.D4(i_controller_cmd[cmd_len*1 + gen_index]),
.D5(i_controller_cmd[cmd_len*2 + gen_index]),
.D6(i_controller_cmd[cmd_len*2 + gen_index]),
.D7(i_controller_cmd[cmd_len*3 + gen_index]),
.D8(i_controller_cmd[cmd_len*3 + gen_index]),
.OQ(oserdes_cmd[gen_index]) // Data path output
);
end
endgenerate
assign o_ddr3_cs_n = oserdes_cmd[CMD_CS_N];
assign o_ddr3_cke = oserdes_cmd[CMD_CKE];
assign o_ddr3_odt = oserdes_cmd[CMD_ODT];
assign o_ddr3_ras_n = oserdes_cmd[CMD_RAS_N],
o_ddr3_cas_n = oserdes_cmd[CMD_CAS_N],
o_ddr3_we_n = oserdes_cmd[CMD_WE_N],
o_ddr3_reset_n = oserdes_cmd[CMD_RESET_N],
o_ddr3_ba_addr = oserdes_cmd[CMD_BANK_START:CMD_ADDRESS_START+1],
o_ddr3_addr = oserdes_cmd[CMD_ADDRESS_START:0];
assign o_ddr3_clk_p = !i_ddr3_clk;
assign o_ddr3_clk_n = i_ddr3_clk;
// PHY data and dm
generate
// Output data: oserdes_soft -> BB
// Input data: BB -> DELAYG -> iserdes_soft
for(gen_index = 0; gen_index < (DQ_BITS*LANES); gen_index = gen_index + 1) begin
oserdes_soft #(.LATTICE_ECP5(LATTICE_ECP5)) oserdes_soft_data(
.CLK(i_ddr3_clk), // High speed clock
.CLKDIV(i_controller_clk), // Divided clock
.RST(sync_rst), // Active high reset
.D1(i_controller_data[gen_index + (DQ_BITS*LANES)*0]),
.D2(i_controller_data[gen_index + (DQ_BITS*LANES)*1]),
.D3(i_controller_data[gen_index + (DQ_BITS*LANES)*2]),
.D4(i_controller_data[gen_index + (DQ_BITS*LANES)*3]),
.D5(i_controller_data[gen_index + (DQ_BITS*LANES)*4]),
.D6(i_controller_data[gen_index + (DQ_BITS*LANES)*5]),
.D7(i_controller_data[gen_index + (DQ_BITS*LANES)*6]),
.D8(i_controller_data[gen_index + (DQ_BITS*LANES)*7]),
.OQ(oserdes_data[gen_index]) // Data path output
);
if(LATTICE_ECP5) begin
BB BB_data (
.I(oserdes_data[gen_index]),
.O(read_dq[gen_index]),
.T(i_controller_dq_tri_control),
.B(io_ddr3_dq[gen_index])
);
DELAYG #(
.DEL_MODE("USER_DEFINED"),
.DEL_VALUE(READ_DATA_DELAY)
) DELAYG_data
(
.A(read_dq[gen_index]),
.Z(idelay_data[gen_index])
);
end // end of LATTICE_ECP5
else begin // XILINX
IOBUF IOBUF_data (
.I(oserdes_data[gen_index]),
.O(read_dq[gen_index]),
.T(i_controller_dq_tri_control),
.IO(io_ddr3_dq[gen_index])
);
IDELAYE2 #(
.DELAY_SRC("IDATAIN"), // Delay input (IDATAIN, DATAIN)
.HIGH_PERFORMANCE_MODE("TRUE"), //Reduced jitter ("TRUE"), Reduced power ("FALSE")
.IDELAY_TYPE("FIXED"), //FIXED, VARIABLE, VAR_LOAD, VAR_LOAD_PIPE
.IDELAY_VALUE(DATA_IDELAY_TAP > 31? 31 : DATA_IDELAY_TAP), //Input delay tap setting (0-31)
.PIPE_SEL("FALSE"), //Select pipelined mode, FALSE, TRUE
.REFCLK_FREQUENCY(200.0), //IDELAYCTRL clock input frequency in MHz (190.0-210.0).
.SIGNAL_PATTERN("DATA") //DATA, CLOCK input signal
)
IDELAYE2_data (
.CNTVALUEOUT(), // 5-bit output: Counter value output
.DATAOUT(idelay_data[gen_index]), // 1-bit output: Delayed data output
.C(i_controller_clk), // 1-bit input: Clock input
.CE(1'b0), // 1-bit input: Active high enable increment/decrement input
.CINVCTRL(1'b0),// 1-bit input: Dynamic clock inversion input
.CNTVALUEIN(0), // 5-bit input: Counter value input
.DATAIN(0), //1-bit input: Internal delay data input
.IDATAIN(read_dq[gen_index]), // 1-bit input: Data input from the I/O
.INC(1'b0), // 1-bit input: Increment / Decrement tap delay input
.LD(0), // 1-bit input: Load IDELAY_VALUE input
.LDPIPEEN(1'b0), // 1-bit input: Enable PIPELINE register to load data input
.REGRST(1'b0) // 1-bit input: Active-high reset tap-delay input
);
end // end of XILINX
iserdes_soft #(.LATTICE_ECP5(LATTICE_ECP5)) iserdes_soft_data(
.CLK(i_ddr3_clk), // High speed clock
.CLKDIV(i_controller_clk), // Divided clock
.RST(sync_rst), // Active high reset
.Q1(o_controller_iserdes_data[(DQ_BITS*LANES)*0 + gen_index]),
.Q2(o_controller_iserdes_data[(DQ_BITS*LANES)*1 + gen_index]),
.Q3(o_controller_iserdes_data[(DQ_BITS*LANES)*2 + gen_index]),
.Q4(o_controller_iserdes_data[(DQ_BITS*LANES)*3 + gen_index]),
.Q5(o_controller_iserdes_data[(DQ_BITS*LANES)*4 + gen_index]),
.Q6(o_controller_iserdes_data[(DQ_BITS*LANES)*5 + gen_index]),
.Q7(o_controller_iserdes_data[(DQ_BITS*LANES)*6 + gen_index]),
.Q8(o_controller_iserdes_data[(DQ_BITS*LANES)*7 + gen_index]),
.D(idelay_data[gen_index]), // Data path output
.bitslip(i_controller_bitslip[gen_index/8])
);
end
// data mask: oserdes -> o_ddr3_dm
for(gen_index = 0; gen_index < LANES; gen_index = gen_index + 1) begin
oserdes_soft #(.LATTICE_ECP5(LATTICE_ECP5)) oserdes_soft_dm(
.CLK(i_ddr3_clk), // High speed clock
.CLKDIV(i_controller_clk), // Divided clock
.RST(sync_rst), // Active high reset
.D1(i_controller_dm[gen_index + LANES*0]),
.D2(i_controller_dm[gen_index + LANES*1]),
.D3(i_controller_dm[gen_index + LANES*2]),
.D4(i_controller_dm[gen_index + LANES*3]),
.D5(i_controller_dm[gen_index + LANES*4]),
.D6(i_controller_dm[gen_index + LANES*5]),
.D7(i_controller_dm[gen_index + LANES*6]),
.D8(i_controller_dm[gen_index + LANES*7]),
.OQ(o_ddr3_dm[gen_index]) // Data path output
);
end
// dqs output: oserdes_soft -> DELAYG -> BB
// dqs input: BB -> DELAYG -> iserdes_soft
for(gen_index = 0; gen_index < LANES; gen_index = gen_index + 1) begin
if(LATTICE_ECP5) begin
// oserdes_soft #(.LATTICE_ECP5(LATTICE_ECP5)) oserdes_soft_dqs_p(
// .CLK(i_ddr3_clk), // High speed clock
// .CLKDIV(i_controller_clk), // Divided clock
// .RST(sync_rst), // Active high reset
// .D1(1'b1),
// .D2(1'b0),
// .D3(1'b1),
// .D4(1'b0),
// .D5(1'b1),
// .D6(1'b0),
// .D7(1'b1),
// .D8(1'b0),
// .OQ(oserdes_dqs_p[gen_index]) // Data path output
// );
// oserdes_soft #(.LATTICE_ECP5(LATTICE_ECP5)) oserdes_soft_dqs_n(
// .CLK(i_ddr3_clk), // High speed clock
// .CLKDIV(i_controller_clk), // Divided clock
// .RST(sync_rst), // Active high reset
// .D1(1'b0), //the last part will still have half dqs series
// .D2(1'b1),
// .D3(1'b0),
// .D4(1'b1),
// .D5(1'b0),
// .D6(1'b1),
// .D7(1'b0),
// .D8(1'b1),
// .OQ(oserdes_dqs_n[gen_index]) // Data path output
// );
// DELAYG #(
// .DEL_MODE("USER_DEFINED")
// ,.DEL_VALUE(WRITE_DQS_DELAY)
// ) DELAYG_odqs_p
// (
// .A(oserdes_dqs_p[gen_index]),
// .Z(odelay_dqs_p[gen_index])
// );
// DELAYG #(
// .DEL_MODE("USER_DEFINED")
// ,.DEL_VALUE(WRITE_DQS_DELAY)
// ) DELAYG_odqs_n
// (
// .A(oserdes_dqs_n[gen_index]),
// .Z(odelay_dqs_n[gen_index])
// );
BB BB_dqs_p (
.I(i_ddr3_clk_90),
.O(),
.T(i_controller_dqs_tri_control),
.B(io_ddr3_dqs[gen_index])
);
BB BB_dqs_n (
.I(!i_ddr3_clk_90),
.O(),
.T(i_controller_dqs_tri_control),
.B(io_ddr3_dqs_n[gen_index])
);
end // end of LATTICE_ECP5
else begin // XILINX
IOBUF IOBUF_dqs_p(
.I(i_ddr3_clk_90),
.O(),
.T(i_controller_dqs_tri_control),
.IO(io_ddr3_dqs[gen_index])
);
IOBUF IOBUF_dqs_n(
.I(!i_ddr3_clk_90),
.O(),
.T(i_controller_dqs_tri_control),
.IO(io_ddr3_dqs_n[gen_index])
);
end // end of XILINX
end
endgenerate
generate
if(!LATTICE_ECP5) begin
IDELAYCTRL IDELAYCTRL_inst (
.RDY(), // 1-bit output: Ready output
.REFCLK(i_ref_clk), // 1-bit input: Reference clock input.The frequency of REFCLK must be 200 MHz to guarantee the tap-delay value specified in the applicable data sheet.
.RST(sync_rst) // 1-bit input: Active high reset input, To ,Minimum Reset pulse width is 52ns
);
end
endgenerate
endmodule

168
rtl/ecp5_phy/iserdes_soft.v Normal file
View File

@ -0,0 +1,168 @@
`default_nettype none
`timescale 1ps / 1ps
module iserdes_soft #(parameter LATTICE_ECP5 = 1) (
input wire CLK, // High-speed clock (data sampling clock)
input wire CLKDIV, // Divided clock (must be synchronous to CLK, typically CLK/4 for DDR)
input wire RST, // Active high reset
output reg Q1, // First data bit
output reg Q2, // Second data bit
output reg Q3, // Third data bit
output reg Q4, // Fourth data bit
output reg Q5, // Fifth data bit
output reg Q6, // Sixth data bit
output reg Q7, // Seventh data bit
output reg Q8, // Eighth data bit
input wire D, // Serialized input data
input wire bitslip // bitslip changes starting_index to shift left the data
);
// Reset signal synchronized to CLKDIV domain
reg reset_clk_div = 1'b1;
reg[2:0] starting_index = 0;
reg [1:0] counter_clk = 2'd0; // 2-bit counter to track which data pair to output
wire [1:0] iq_pair; // 2-bit register to hold deserialized data input
reg Q1_clk = 0,
Q2_clk = 0,
Q3_clk = 0,
Q4_clk = 0,
Q5_clk = 0,
Q6_clk = 0,
Q7_clk = 0,
Q8_clk = 0;
reg[7:0] Q_clk, Q_clk_temp;
// Synchronize reset signal to CLKDIV domain
always @(posedge CLKDIV) begin
if (RST) begin
reset_clk_div <= 1'b1;
starting_index <= 3'd0;
end else begin
reset_clk_div <= 1'b0;
starting_index <= bitslip? starting_index + 1 : starting_index; // increment when bitslip is issued
end
end
// 2-bit counter increments on each CLK cycle to select the correct data pair
always @(posedge CLK) begin
if (reset_clk_div) begin
counter_clk <= 0; // Reset counter when reset is active
end else begin
counter_clk <= counter_clk + 2'd1; // Increment counter every clock cycle
end
end
// Capture and store deserialized data pairs
always @(posedge CLK) begin
case (counter_clk)
2'd0: begin // First 2 bits
Q1_clk <= iq_pair[0];
Q2_clk <= iq_pair[1];
if(starting_index == 6) begin
Q_clk <= Q_clk_temp; // 3 -> 0 -> 1 -> 2: {2,1.0,3}
end
if(starting_index == 7) begin
Q_clk <= {Q7_clk,Q_clk_temp[6:0]}; // [7] is relevant
end
if(starting_index == 0) begin
Q_clk_temp <= {Q8_clk, Q7_clk, Q6_clk, Q5_clk, Q4_clk, Q3_clk, Q2_clk, Q1_clk}; // 0 -> 1 -> 2 -> 3: {3,2,1,0}
end
if(starting_index == 1) begin
Q_clk_temp <= {Q1_clk, Q8_clk, Q7_clk, Q6_clk, Q5_clk, Q4_clk, Q3_clk, Q2_clk}; // [6:0]] lsb is relevant
end
end
2'd1: begin // Second 2 bits
Q3_clk <= iq_pair[0];
Q4_clk <= iq_pair[1];
if(starting_index == 0) begin
Q_clk <= Q_clk_temp; // 0 -> 1 -> 2 -> 3: {3,2,1,0}
end
if(starting_index == 1) begin
Q_clk <= {Q1_clk,Q_clk_temp[6:0]}; // [7] is relevant
end
if(starting_index == 2) begin
Q_clk_temp <= {Q2_clk, Q1_clk, Q8_clk, Q7_clk, Q6_clk, Q5_clk, Q4_clk, Q3_clk}; // 1 -> 2 -> 3 -> 0: {0,3,2,1}
end
if(starting_index == 3) begin
Q_clk_temp <= {Q3_clk, Q2_clk, Q1_clk, Q8_clk, Q7_clk, Q6_clk, Q5_clk, Q4_clk}; // [6:0] is relevant
end
end
2'd2: begin // Third 2 bits
Q5_clk <= iq_pair[0];
Q6_clk <= iq_pair[1];
if(starting_index == 2) begin
Q_clk <= Q_clk_temp; // 1 -> 2 -> 3 -> 0: {0,3,2,1}
end
if(starting_index == 3) begin
Q_clk <= {Q3_clk,Q_clk_temp[6:0]}; // [7] is relevant
end
if(starting_index == 4) begin
Q_clk_temp <= {Q4_clk, Q3_clk, Q2_clk, Q1_clk, Q8_clk, Q7_clk, Q6_clk, Q5_clk}; // 2 -> 3 -> 0 -> 1: {1,0.3,2}
end
if(starting_index == 5) begin
Q_clk_temp <= {Q5_clk, Q4_clk, Q3_clk, Q2_clk, Q1_clk, Q8_clk, Q7_clk, Q6_clk}; // 2 -> 3 -> 0 -> 1: {1,0.3,2}
end
end
2'd3: begin // Fourth 2 bits
Q7_clk <= iq_pair[0];
Q8_clk <= iq_pair[1];
if(starting_index == 4) begin
Q_clk <= Q_clk_temp; // 2 -> 3 -> 0 -> 1: {1,0.3,2}
end
if(starting_index == 5) begin
Q_clk <= {Q5_clk,Q_clk_temp[6:0]}; // [7] is relevant
end
if(starting_index == 6) begin
Q_clk_temp <= {Q6_clk, Q5_clk, Q4_clk, Q3_clk, Q2_clk, Q1_clk, Q8_clk, Q7_clk}; // 3 -> 0 -> 1 -> 2: {2,1.0,3}
end
if(starting_index == 7) begin
Q_clk_temp <= {Q7_clk, Q6_clk, Q5_clk, Q4_clk, Q3_clk, Q2_clk, Q1_clk, Q8_clk}; // 3 -> 0 -> 1 -> 2: {2,1.0,3}
end
// once counter_clk 0-to-3 is done, then the whole 8-bit data is complete thus we store it to Q_clk
// Q_clk will then be sampled by next CLKDIV posedge
// This makes sure the CLKDIV posedge samples only once counter_clk 0-to-3 is complete
end
endcase
end
// register the Q*_clk to CLKDIV domain
always @(posedge CLKDIV) begin
// 0
Q1 <= Q_clk[0];
Q2 <= Q_clk[1];
// 1
Q3 <= Q_clk[2];
Q4 <= Q_clk[3];
// 2
Q5 <= Q_clk[4];
Q6 <= Q_clk[5];
// 3
Q7 <= Q_clk[6];
Q8 <= Q_clk[7];
end
generate
if(LATTICE_ECP5) begin
// Instantiate input DDR flip-flop to capture serialized data
IDDRX1F IDDRX1F_inst (
.SCLK(CLK),
.RST(reset_clk_div),
.Q0(iq_pair[0]),
.Q1(iq_pair[1]),
.D(D)
);
end
else begin // XILINX
IDDR
#(.DDR_CLK_EDGE("OPPOSITE_EDGE")) IDDR_inst
(
.Q1(iq_pair[0]), // 1-bit output for positive edge of clock
.Q2(iq_pair[1]), // 1-bit output for negative edge of clock
.C(CLK), // 1-bit clock input
.CE(1'b1), // 1-bit clock enable input
.D(D), // 1-bit DDR data input
.R(reset_clk_div), // 1-bit reset
.S(1'b0) // 1-bit set
);
end
endgenerate
endmodule

View File

@ -0,0 +1,78 @@
`default_nettype none
`timescale 1ps / 1ps
module oserdes_soft #(parameter LATTICE_ECP5 = 1) (
input wire CLK, // High-speed clock (data sampling clock)
input wire CLKDIV, // Divided clock (must be synchronous to CLK, typically CLK/4 for DDR)
input wire RST, // Active high reset
input wire D1, // First data bit
input wire D2, // Second data bit
input wire D3, // Third data bit
input wire D4, // Fourth data bit
input wire D5, // Fifth data bit
input wire D6, // Sixth data bit
input wire D7, // Seventh data bit
input wire D8, // Eighth data bit
output wire OQ // Serialized output data
);
// Reset signal synchronized to CLKDIV domain
reg reset_clk_div = 1'b1;
reg[1:0] counter_clk = 2'd0; // 2-bit counter to track which data pair to output
reg[1:0] oq_pair = 2'd0; // 2-bit register to hold serialized data output
// Synchronize reset signal to CLKDIV domain
always @(posedge CLKDIV) begin
if (RST) begin
reset_clk_div <= 1'b1;
end else begin
reset_clk_div <= 1'b0;
end
end
// 2-bit counter increments on each CLK cycle to select the correct data pair
always @(posedge CLK) begin
if (reset_clk_div) begin
counter_clk <= 2'd0; // Reset counter when reset is active
end else begin
counter_clk <= counter_clk + 2'd1; // Increment counter every clock cycle
end
end
// Multiplexer logic: Selects two bits at a time from the 8-bit input data
always @(posedge CLK) begin
case (counter_clk)
2'd0: oq_pair <= {D2, D1}; // First 2 bits
2'd1: oq_pair <= {D4, D3}; // Second 2 bits
2'd2: oq_pair <= {D6, D5}; // Third 2 bits
2'd3: oq_pair <= {D8, D7}; // Fourth 2 bits
endcase
end
generate
if(LATTICE_ECP5) begin
// Instantiating ODDRX1F primitive for DDR output data serialization
ODDRX1F ODDRX1F_inst (
.SCLK(CLK), // High-speed clock
.RST(reset_clk_div), // Reset signal synchronized to CLKDIV
.D0(oq_pair[0]), // First bit of selected pair
.D1(oq_pair[1]), // Second bit of selected pair
.Q(OQ) // Serialized DDR output
);
end
else begin // XILINX
ODDR
#(.DDR_CLK_EDGE("SAME_EDGE")) ODDR_inst
(
.C(CLK), // High-speed clock
.R(reset_clk_div), // Reset signal synchronized to CLKDIV
.S(1'b0), // Set
.CE(1'b1),
.D1(oq_pair[0]), // First bit of selected pair
.D2(oq_pair[1]), // Second bit of selected pair
.Q(OQ) // Serialized DDR output
);
end
endgenerate
endmodule

View File

@ -137,6 +137,7 @@ module ddr3 (
parameter feature_odt_hi = 0;
parameter PERTCKAVG=TDLLK;
parameter FLY_BY_DELAY = 0, DQ_DELAY = 0;
parameter[0:0] DLL_OFF = 0;
// text macros
`define DQ_PER_DQS DQ_BITS/DQS_BITS
@ -1662,7 +1663,7 @@ module ddr3 (
$display ("%m at time %t WARNING: 500 us is required after RST_N goes inactive before CKE goes active.", $time);
tm_txpr <= $time;
ck_txpr <= ck_cntr;
init_step = init_step + 1;
init_step = init_step + 2;
end
1 : begin
if (dll_en) init_step = init_step + 1;
@ -1770,7 +1771,7 @@ module ddr3 (
for (i=0; i<64; i=i+1) begin
if (dq_in_valid && dll_locked && ($time - tm_dqs_neg[i] < $rtoi(TDSS*tck_avg)))
$display ("%m: at time %t ERROR: tDSS violation on %s bit %d", $time, dqs_string[i/32], i%32);
if (check_write_dqs_high[i])
if (check_write_dqs_high[i] && !DLL_OFF)
$display ("%m: at time %t ERROR: %s bit %d latching edge required during the preceding clock period.", $time, dqs_string[i/32], i%32);
end
check_write_dqs_high <= 0;
@ -1781,7 +1782,7 @@ module ddr3 (
if ((tm_tdqss < tck_avg/2.0) && (tm_tdqss > TDQSS*tck_avg))
$display ("%m: at time %t ERROR: tDQSS violation on %s bit %d", $time, dqs_string[i/32], i%32);
end
if (check_write_dqs_low[i])
if (check_write_dqs_low[i] && !DLL_OFF)
$display ("%m: at time %t ERROR: %s bit %d latching edge required during the preceding clock period", $time, dqs_string[i/32], i%32);
end
check_write_preamble <= 0;
@ -2249,8 +2250,8 @@ module ddr3 (
$display ("%m: at time %t ERROR: tJIT(cc) violation by %f ps.", $time, abs_value(tjit_cc_time) - TJIT_CC);
if (TCK_MIN - tck_avg >= 1.0)
$display ("%m: at time %t ERROR: tCK(avg) minimum violation by %f ps.", $time, TCK_MIN - tck_avg);
if (tck_avg - TCK_MAX >= 1.0)
$display ("%m: at time %t ERROR: tCK(avg) maximum violation by %f ps.", $time, tck_avg - TCK_MAX);
if ((tck_avg - TCK_MAX >= 1.0) && !DLL_OFF)
$display ("%m: at time %t ERROR: tCK(avg) maximum violation by %f ps.", $time, tck_avg - TCK_MAX);
// check tCL
if (tm_ck_neg - $time < TCL_ABS_MIN*tck_avg)
@ -2800,7 +2801,7 @@ module ddr3 (
check_write_postamble[i] <= 1'b0;
check_write_dqs_low[i] <= 1'b0;
tm_dqs[i%32] <= $time;
end else begin
end else if(!DLL_OFF) begin
$display ("%m: at time %t ERROR: Invalid latching edge on %s bit %d", $time, dqs_string[i/32], i%32);
end
end
@ -2906,7 +2907,7 @@ module ddr3 (
end
check_dm_tdipw[i%32] <= 1'b1;
tm_dqs[i%32] <= $time;
end else begin
end else if(!DLL_OFF) begin
$display ("%m: at time %t ERROR: Invalid latching edge on %s bit %d", $time, dqs_string[i/32], i%32);
end
end

View File

@ -57,16 +57,16 @@ module ddr3_dimm_micron_sim;
`endif
localparam CONTROLLER_CLK_PERIOD = 5_000, //ps, period of clock input to this DDR3 controller module
DDR3_CLK_PERIOD = 1_250, //ps, period of clock input to DDR3 RAM device
localparam CONTROLLER_CLK_PERIOD = 12_000, //ps, period of clock input to this DDR3 controller module
DDR3_CLK_PERIOD = 3_000, //ps, period of clock input to DDR3 RAM device
AUX_WIDTH = 16, // AUX lines
ECC_ENABLE = 0, // ECC enable
SELF_REFRESH = 2'b00,
DUAL_RANK_DIMM = 0,
TEST_SELF_REFRESH = 0,
SECOND_WISHBONE = 0,
BIST_MODE = 1; // 0 = No BIST, 1 = run through all address space ONCE , 2 = run through all address space for every test (burst w/r, random w/r, alternating r/w)
BIST_MODE = 2, // 0 = No BIST, 1 = run through all address space ONCE , 2 = run through all address space for every test (burst w/r, random w/r, alternating r/w)
DLL_OFF = 1;
reg i_controller_clk, i_ddr3_clk, i_ref_clk, i_ddr3_clk_90;
reg i_rst_n;
@ -171,7 +171,8 @@ ddr3_top #(
.WB_ERROR(1), // set to 1 to support Wishbone error (asserts at ECC double bit error)
.BIST_MODE(BIST_MODE), // 0 = No BIST, 1 = run through all address space ONCE , 2 = run through all address space for every test (burst w/r, random w/r, alternating r/w)
.SELF_REFRESH(SELF_REFRESH), // 0 = use i_user_self_refresh input, 1 = Self-refresh mode is enabled after 64 controller clock cycles of no requests, 2 = 128 cycles, 3 = 256 cycles
.DUAL_RANK_DIMM(DUAL_RANK_DIMM) // enable dual rank DIMM (1 = enable, 0 = disable)
.DUAL_RANK_DIMM(DUAL_RANK_DIMM), // enable dual rank DIMM (1 = enable, 0 = disable)
.DLL_OFF(DLL_OFF) // 1 = DLL off for low frequency ddr3 clock
) ddr3_top
(
//clock and reset
@ -227,7 +228,7 @@ ddr3_top #(
`ifdef TWO_LANES_x8
// 1 lane DDR3
ddr3 ddr3_0(
ddr3 #(.DLL_OFF(DLL_OFF)) ddr3_0(
.rst_n(reset_n),
.ck(o_ddr3_clk_p[0]),
.ck_n(o_ddr3_clk_n[0]),
@ -249,7 +250,7 @@ ddr3_top #(
`ifdef EIGHT_LANES_x8
// DDR3 Device
ddr3_module ddr3_module(
ddr3_module #(.DLL_OFF(DLL_OFF)) ddr3_module(
.reset_n(reset_n),
.ck(o_ddr3_clk_p), //[1:0]
.ck_n(o_ddr3_clk_n), //[1:0]

View File

@ -87,6 +87,8 @@ module ddr3_module (
input scl ; // no connect
inout sda ; // no connect
parameter DLL_OFF = 0;
`ifdef QUAD_RANK
initial if (DEBUG) $display("%m: Quad Rank");
`elsif DUAL_RANK
@ -304,14 +306,14 @@ module ddr3_module (
`endif
`elsif x8
initial if (DEBUG) $display("%m: Component Width = x8");
ddr3 #(.FLY_BY_DELAY(FLY_BY_DELAY_LANE_0)) U1R0 (reset_n, rck[0], rck_n[0], rcke[0], rs_n[0], rras_n, rcas_n, rwe_n, dqs[ 9] , rba, raddr[ADDR_BITS-1:0], dq [ 7: 0], dqs[ 0] , dqs_n[ 0] , dqs_n[ 9], rodt[0]);
ddr3 #(.FLY_BY_DELAY(FLY_BY_DELAY_LANE_1)) U2R0 (reset_n, rck[0], rck_n[0], rcke[0], rs_n[0], rras_n, rcas_n, rwe_n, dqs[10] , rba, raddr[ADDR_BITS-1:0], dq [15: 8], dqs[ 1] , dqs_n[ 1] , dqs_n[10], rodt[0]);
ddr3 #(.FLY_BY_DELAY(FLY_BY_DELAY_LANE_2)) U3R0 (reset_n, rck[0], rck_n[0], rcke[0], rs_n[0], rras_n, rcas_n, rwe_n, dqs[11] , rba, raddr[ADDR_BITS-1:0], dq [23:16], dqs[ 2] , dqs_n[ 2] , dqs_n[11], rodt[0]);
ddr3 #(.FLY_BY_DELAY(FLY_BY_DELAY_LANE_3)) U4R0 (reset_n, rck[0], rck_n[0], rcke[0], rs_n[0], rras_n, rcas_n, rwe_n, dqs[12] , rba, raddr[ADDR_BITS-1:0], dq [31:24], dqs[ 3] , dqs_n[ 3] , dqs_n[12], rodt[0]);
ddr3 #(.FLY_BY_DELAY(FLY_BY_DELAY_LANE_4)) U6R0 (reset_n, rck[0], rck_n[0], rcke[0], rs_n[0], rras_n, rcas_n, rwe_n, dqs[13] , rba, raddr[ADDR_BITS-1:0], dq [39:32], dqs[ 4] , dqs_n[ 4] , dqs_n[13], rodt[0]);
ddr3 #(.FLY_BY_DELAY(FLY_BY_DELAY_LANE_5)) U7R0 (reset_n, rck[0], rck_n[0], rcke[0], rs_n[0], rras_n, rcas_n, rwe_n, dqs[14] , rba, raddr[ADDR_BITS-1:0], dq [47:40], dqs[ 5] , dqs_n[ 5] , dqs_n[14], rodt[0]);
ddr3 #(.FLY_BY_DELAY(FLY_BY_DELAY_LANE_6)) U8R0 (reset_n, rck[0], rck_n[0], rcke[0], rs_n[0], rras_n, rcas_n, rwe_n, dqs[15] , rba, raddr[ADDR_BITS-1:0], dq [55:48], dqs[ 6] , dqs_n[ 6] , dqs_n[15], rodt[0]);
ddr3 #(.FLY_BY_DELAY(FLY_BY_DELAY_LANE_7)) U9R0 (reset_n, rck[0], rck_n[0], rcke[0], rs_n[0], rras_n, rcas_n, rwe_n, dqs[16] , rba, raddr[ADDR_BITS-1:0], dq [63:56], dqs[ 7] , dqs_n[ 7] , dqs_n[16], rodt[0]);
ddr3 #(.FLY_BY_DELAY(FLY_BY_DELAY_LANE_0), .DLL_OFF(DLL_OFF)) U1R0 (reset_n, rck[0], rck_n[0], rcke[0], rs_n[0], rras_n, rcas_n, rwe_n, dqs[ 9] , rba, raddr[ADDR_BITS-1:0], dq [ 7: 0], dqs[ 0] , dqs_n[ 0] , dqs_n[ 9], rodt[0]);
ddr3 #(.FLY_BY_DELAY(FLY_BY_DELAY_LANE_1), .DLL_OFF(DLL_OFF)) U2R0 (reset_n, rck[0], rck_n[0], rcke[0], rs_n[0], rras_n, rcas_n, rwe_n, dqs[10] , rba, raddr[ADDR_BITS-1:0], dq [15: 8], dqs[ 1] , dqs_n[ 1] , dqs_n[10], rodt[0]);
ddr3 #(.FLY_BY_DELAY(FLY_BY_DELAY_LANE_2), .DLL_OFF(DLL_OFF)) U3R0 (reset_n, rck[0], rck_n[0], rcke[0], rs_n[0], rras_n, rcas_n, rwe_n, dqs[11] , rba, raddr[ADDR_BITS-1:0], dq [23:16], dqs[ 2] , dqs_n[ 2] , dqs_n[11], rodt[0]);
ddr3 #(.FLY_BY_DELAY(FLY_BY_DELAY_LANE_3), .DLL_OFF(DLL_OFF)) U4R0 (reset_n, rck[0], rck_n[0], rcke[0], rs_n[0], rras_n, rcas_n, rwe_n, dqs[12] , rba, raddr[ADDR_BITS-1:0], dq [31:24], dqs[ 3] , dqs_n[ 3] , dqs_n[12], rodt[0]);
ddr3 #(.FLY_BY_DELAY(FLY_BY_DELAY_LANE_4), .DLL_OFF(DLL_OFF)) U6R0 (reset_n, rck[0], rck_n[0], rcke[0], rs_n[0], rras_n, rcas_n, rwe_n, dqs[13] , rba, raddr[ADDR_BITS-1:0], dq [39:32], dqs[ 4] , dqs_n[ 4] , dqs_n[13], rodt[0]);
ddr3 #(.FLY_BY_DELAY(FLY_BY_DELAY_LANE_5), .DLL_OFF(DLL_OFF)) U7R0 (reset_n, rck[0], rck_n[0], rcke[0], rs_n[0], rras_n, rcas_n, rwe_n, dqs[14] , rba, raddr[ADDR_BITS-1:0], dq [47:40], dqs[ 5] , dqs_n[ 5] , dqs_n[14], rodt[0]);
ddr3 #(.FLY_BY_DELAY(FLY_BY_DELAY_LANE_6), .DLL_OFF(DLL_OFF)) U8R0 (reset_n, rck[0], rck_n[0], rcke[0], rs_n[0], rras_n, rcas_n, rwe_n, dqs[15] , rba, raddr[ADDR_BITS-1:0], dq [55:48], dqs[ 6] , dqs_n[ 6] , dqs_n[15], rodt[0]);
ddr3 #(.FLY_BY_DELAY(FLY_BY_DELAY_LANE_7), .DLL_OFF(DLL_OFF)) U9R0 (reset_n, rck[0], rck_n[0], rcke[0], rs_n[0], rras_n, rcas_n, rwe_n, dqs[16] , rba, raddr[ADDR_BITS-1:0], dq [63:56], dqs[ 7] , dqs_n[ 7] , dqs_n[16], rodt[0]);
`ifdef ECC
ddr3 U5R0 (reset_n, rck[0], rck_n[0], rcke[0], rs_n[0], rras_n, rcas_n, rwe_n, dqs[17] , rba, raddr[ADDR_BITS-1:0], rcb[ 7: 0], dqs[ 8] , dqs_n[ 8] , dqs_n[17], rodt[0]);
`endif

View File

@ -561,7 +561,7 @@
<spirit:parameters>
<spirit:parameter>
<spirit:name>viewChecksum</spirit:name>
<spirit:value>407441e6</spirit:value>
<spirit:value>e9061c47</spirit:value>
</spirit:parameter>
</spirit:parameters>
</spirit:view>
@ -577,7 +577,7 @@
<spirit:parameters>
<spirit:parameter>
<spirit:name>viewChecksum</spirit:name>
<spirit:value>407441e6</spirit:value>
<spirit:value>e9061c47</spirit:value>
</spirit:parameter>
</spirit:parameters>
</spirit:view>
@ -1596,7 +1596,7 @@
<spirit:vendorExtensions>
<xilinx:portInfo>
<xilinx:enablement>
<xilinx:isEnabled xilinx:resolve="dependent" xilinx:id="PORT_ENABLEMENT.i_user_self_refresh" xilinx:dependency="$SELF_REFRESH = 0">false</xilinx:isEnabled>
<xilinx:isEnabled xilinx:resolve="dependent" xilinx:id="PORT_ENABLEMENT.i_user_self_refresh" xilinx:dependency="$SELF_REFRESH = 0">true</xilinx:isEnabled>
</xilinx:enablement>
</xilinx:portInfo>
</spirit:vendorExtensions>
@ -1676,7 +1676,7 @@
<spirit:modelParameter spirit:dataType="integer">
<spirit:name>SELF_REFRESH</spirit:name>
<spirit:displayName>Self-Refresh</spirit:displayName>
<spirit:value spirit:format="bitString" spirit:resolve="generated" spirit:id="MODELPARAM_VALUE.SELF_REFRESH" spirit:bitStringLength="2">&quot;00&quot;</spirit:value>
<spirit:value spirit:format="long" spirit:resolve="generated" spirit:id="MODELPARAM_VALUE.SELF_REFRESH">0</spirit:value>
</spirit:modelParameter>
<spirit:modelParameter spirit:dataType="integer">
<spirit:name>DIC</spirit:name>
@ -1826,7 +1826,7 @@
<spirit:file>
<spirit:name>../rtl/axi/ddr3_top_axi.v</spirit:name>
<spirit:fileType>verilogSource</spirit:fileType>
<spirit:userFileType>CHECKSUM_f9ca4d9d</spirit:userFileType>
<spirit:userFileType>CHECKSUM_8c69a3da</spirit:userFileType>
</spirit:file>
</spirit:fileSet>
<spirit:fileSet>
@ -2103,7 +2103,7 @@
<spirit:parameter>
<spirit:name>SELF_REFRESH</spirit:name>
<spirit:displayName>Self-Refresh</spirit:displayName>
<spirit:value spirit:resolve="user" spirit:id="PARAM_VALUE.SELF_REFRESH" spirit:choiceRef="choice_pairs_96a879b9" spirit:bitStringLength="2">&quot;00&quot;</spirit:value>
<spirit:value spirit:format="long" spirit:resolve="user" spirit:id="PARAM_VALUE.SELF_REFRESH" spirit:choiceRef="choice_pairs_96a879b9">0</spirit:value>
</spirit:parameter>
<spirit:parameter>
<spirit:name>BIST_MODE</spirit:name>
@ -2143,8 +2143,8 @@
<xilinx:displayName>uberddr3_axi_v1_0</xilinx:displayName>
<xilinx:definitionSource>package_project</xilinx:definitionSource>
<xilinx:vendorURL>https://github.com/AngeloJacobo/UberDDR3</xilinx:vendorURL>
<xilinx:coreRevision>12</xilinx:coreRevision>
<xilinx:coreCreationDateTime>2025-02-16T03:52:36Z</xilinx:coreCreationDateTime>
<xilinx:coreRevision>13</xilinx:coreRevision>
<xilinx:coreCreationDateTime>2025-04-19T05:56:34Z</xilinx:coreCreationDateTime>
<xilinx:tags>
<xilinx:tag xilinx:name="nopcore"/>
</xilinx:tags>
@ -2153,10 +2153,10 @@
<xilinx:xilinxVersion>2022.1</xilinx:xilinxVersion>
<xilinx:checksum xilinx:scope="busInterfaces" xilinx:value="6c0c2bc0"/>
<xilinx:checksum xilinx:scope="memoryMaps" xilinx:value="cd65c31e"/>
<xilinx:checksum xilinx:scope="fileGroups" xilinx:value="de319895"/>
<xilinx:checksum xilinx:scope="ports" xilinx:value="4c100aa3"/>
<xilinx:checksum xilinx:scope="hdlParameters" xilinx:value="a0261d6d"/>
<xilinx:checksum xilinx:scope="parameters" xilinx:value="ab77e269"/>
<xilinx:checksum xilinx:scope="fileGroups" xilinx:value="cbfe0484"/>
<xilinx:checksum xilinx:scope="ports" xilinx:value="abd96048"/>
<xilinx:checksum xilinx:scope="hdlParameters" xilinx:value="42d1c32d"/>
<xilinx:checksum xilinx:scope="parameters" xilinx:value="0021d062"/>
</xilinx:packagingInfo>
</spirit:vendorExtensions>
</spirit:component>