added example demo for orangecrab ecp5

This commit is contained in:
AngeloJacobo 2025-04-19 13:30:40 +08:00
parent b990372663
commit baaa2a2482
6 changed files with 949 additions and 0 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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