added example demo for orangecrab ecp5
This commit is contained in:
parent
b990372663
commit
baaa2a2482
|
|
@ -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
|
||||
Loading…
Reference in New Issue