Merge pull request #30 from AngeloJacobo/ecp5_phy
added support for lattice ecp5 PHY, now working on orangecrab ECP5
This commit is contained in:
commit
264801fc99
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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 ;
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
171
rtl/ddr3_top.v
171
rtl/ddr3_top.v
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -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">"00"</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">"00"</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>
|
||||
|
|
|
|||
Loading…
Reference in New Issue