This page describes steps you need to take in order to incorporate this HyperRAM controller into your design.
The HyperRAM internal state machine has been written in pure RTL (i.e. as portable as possible), making use of only rising edge flip flops and no other IP blocks, and should be trivially portable.
However, the input and output drivers make heavy use of AMD/Xilinx-specific primitives and constraints, so these need to be manually ported when choosing other vendors,
Below, the following aspects are discussed in detail:
- Tri-state buffering
- Clocking
- Constraints
The HyperRAM device uses bidirectional ports, and this requires I/O buffers
with tri-state capability for the wires RWDS
and DQ
. Vivado can
automatically infer tri-state buffers when assigning 'Z'
to a port declared
as inout
. It is good design practice to infer the tri-state buffers from the
top-level file. Therefore, this HyperRAM controller does not itself infer any
tri-state buffers. Instead, it contains three signals for each of the RWDS
and
DQ
wires: One for input, one for output, and one for output enable.
In the top-level file of your own project you should include the following lines:
hr_rwds_io <= hr_rwds_out when hr_rwds_oe = '1' else 'Z';
hr_dq_io <= hr_dq_out when hr_dq_oe = '1' else (others => 'Z');
hr_rwds_in <= hr_rwds_io;
hr_dq_in <= hr_dq_io;
Here hr_rwds_io
and hr_dq_io
are the external ports connected to the HyperRAM
device.
The HyperRAM implementation requires a total of three clocks:
clk_i
: This runs at 100 MHz, and drives the Avalon MM interface as well as the HyperRAM device.clk_del_i
: This must be synchronous toclk_i
with a 90 degree phase shift.delay_refclk_i
: This runs at 200 Mhz.
All three clocks should be generated from the same MMCM/PLL.
See the file src/Example_Design/clk.vhd for how clock synthesis is done on the MEGA65.
A number of constraints are needed by the HyperRAM controller in order to function properly.
On the transmit side (from FPGA to HyperRAM) we set the IOB property to TRUE on all the
output ports (RSTN
, CSN
, RWDS
, and DQ
). This ensures the output registers are part
of the output buffer, which minimizes the delay inside the FPGA. Note the CK
signal is
already controlled directly by an ODDR buffer.
set_property IOB TRUE [get_cells i_core/i_hyperram/hyperram_tx_inst/hr_rwds_oe_n_reg ]
set_property IOB TRUE [get_cells i_core/i_hyperram/hyperram_tx_inst/hr_dq_oe_n_reg[*] ]
set_property IOB TRUE [get_cells i_core/i_hyperram/hyperram_ctrl_inst/hb_csn_o_reg ]
set_property IOB TRUE [get_cells i_core/i_hyperram/hyperram_ctrl_inst/hb_rstn_o_reg ]
On the receive side (from HyperRAM to FPGA) we need several extra constraints. First, we
want to avoid having an extra BUFG on the RWDS_DELAY
. This will happen automatically,
because Vivado recognizes this signal is used as a clock. However, with the IDELAY block
we are manually controlling the delay of this signal, and any extra inserted BUFG will
increase the delay many times.
set_property CLOCK_BUFFER_TYPE NONE [get_nets -of [get_pins i_core/i_hyperram/hyperram_rx_inst/delay_rwds_inst/DATAOUT]]
Secondly, the data path into the Rx FIFO must be as short as possible, so extra constraints are needed for that.
set_max_delay 2 -datapath_only -from [get_cells i_core/i_hyperram/hyperram_ctrl_inst/hb_read_o_reg]
set_max_delay 2 -datapath_only -from [get_cells i_core/i_hyperram/hyperram_rx_inst/iddr_dq_gen[*].iddr_dq_inst]
See the file src/Example_Design/top.xdc for the full set of constraints needed.