Galatea PCI Express Spartan 6 FPGA Module

Simple DDR3 Interfacing on Galatea using Xilinx MIG 6

2250 views March 8, 2018 admin 7

Introduction

The purpose of this article is to help readers understand how to use DDR3 memory available on Galatea using Xilinx MIG 6 IP core easily. The MIG 6 IP core provides users with two options to interface with memory: User Interface (a wrapper over Native interface) and the AXI4 Interface.  This article will demonstrate how to write to the DDR3 memory on Galatea using simple Verilog code and then read back the data. The design will compare the data written to DDR3 and the data read back from it. The verification and DDR3 calibration results are indicated using GPIO pins on Galatea header P4.

Prerequisites

Let’s get started

The following steps will walk you through the process of creating a simple DDR3 project using Xilinx ISE Design Suite.

Step 1:

Open Xilinx ISE Design Suite and select “New Project” from “File” menu.  The “New Project Wizard” window will open. Type in a project name and select a convenient project location. In this article, author used “galatea-simple-ddr3-tutorial” as the project name. Click “Next” to proceed.

Step 2:

Specify the device and project settings (Family: Spartan 6, Device: XC6SLX45T, Package: FGG484 and Speed grade: -3) in “Project Settings” step as shown below. Click “Next” and “Finish”. A new ISE project will open with the selected settings.

Step 3:

Under “Design” tab, right click and click “New Source”. Select “IP (CORE Generator & Architecture Wizard)”, type “File Name” as “mem” and click “Next” to proceed. Select the “MIG IP” from “Select IP” tab, click “Next” and “Finish”. The “Xilinx Memory Interface Generator” dialog will open. Click “Next” for three consecutive times and select the “Memory Type” as “DDR3 SDRAM” on both banks (1 & 3) as shown below. Galatea features two on-board DDR3 SDRAM memories, one of Bank 1 and the other on Bank 3. As shown below, C3 is controller for Bank 3 and C1 is controller for Bank 1. Click “Next”.

Step 4:

In the “Options for C1”, select “Frequency” as “3000 ps” and “Memory Type” as “MT41J128M16XX-125” . Click “Next” and select the same settings in case of “Options for C3”. Click “Next” and keep the default settings. Again leave the settings to default by clicking on the “Next”. Select Port Configuration for C1 as “one 128-bit bi-directional port”, click “Next” and select the same for C3 Port configuration. Click “Next” further three times. Select the FPGA options for C1 as follows and click “Next” to proceed.

Select the FPGA options for C3 as follows and click “Next” to proceed.

Accept the license by clicking on the “Next” twice. Click “Next” twice and “Generate” to create MIG IP core.

Step 5:

Create a Verilog file with .v extension and copy paste the following code in “galatea_ddr3.v” to run simple DDR3 with the user interface.

The following code uses MIG 6 IP core and the input clock for the MIG is provided by the system clock directly which is 100MHz. The two separate system clocks (100MHz) are provided for two DDR3 memories which are available on Bank 1 and Bank 3 of Galatea.

In the following Verilog code, user design and the MIG IP core are instantiated. The user design is instantiated twice to interface with the two DDR3 memory interface controllers which are C1 (for DDR3 memory available on Bank1) and C3 (for DDR3 memory available on Bank3).

////////////////////////////////////////////////////////////////////
// File Name: galate_ddr3.v                                      
// Description: Instantiation of MIG and user design for C1 and C3
////////////////////////////////////////////////////////////////////
module galatea_ddr3(
 input   c3_sys_clk,
 input   c1_sys_clk,
 input   c_sys_rst_i,
 inout   [15:0] mcb3_dram_dq,
 output  [13:0] mcb3_dram_a,
 output  [2:0]  mcb3_dram_ba,
 output  mcb3_dram_ras_n,
 output  mcb3_dram_cas_n,
 output  mcb3_dram_we_n,
 output  mcb3_dram_odt,
 output  mcb3_dram_reset_n,
 output  mcb3_dram_cke,
 output  mcb3_dram_dm,
 inout   mcb3_dram_udqs,
 inout   mcb3_dram_udqs_n,
 inout   mcb3_rzq,
 inout   mcb3_zio,
 output  mcb3_dram_udm,
 inout   mcb3_dram_dqs,
 inout   mcb3_dram_dqs_n,
 output  mcb3_dram_ck,
 output  mcb3_dram_ck_n,
 
 inout   [15:0] mcb1_dram_dq,
 output  [13:0] mcb1_dram_a,
 output  [2:0] mcb1_dram_ba,
 output  mcb1_dram_ras_n,
 output  mcb1_dram_cas_n,
 output  mcb1_dram_we_n,
 output  mcb1_dram_odt,
 output  mcb1_dram_reset_n,
 output  mcb1_dram_cke,
 output  mcb1_dram_dm,
 inout   mcb1_dram_udqs,
 inout   mcb1_dram_udqs_n,
 inout   mcb1_rzq,
 inout   mcb1_zio,
 output  mcb1_dram_udm,
 inout   mcb1_dram_dqs,
 inout   mcb1_dram_dqs_n,
 output  mcb1_dram_ck,
 output  mcb1_dram_ck_n,
 
 output  led1_calib,
 output  led1_pass,
 output  led1_fail,
 output  led3_calib,
 output  led3_pass,
 output  led3_fail
 );
 
 // Command Signals
 wire [2:0]  c3_p0_cmd_instr;
 wire [5:0]  c3_p0_cmd_bl;
 wire [29:0] c3_p0_cmd_byte_addr;
 wire [2:0]  c1_p0_cmd_instr;
 wire [5:0]  c1_p0_cmd_bl;
 wire [29:0] c1_p0_cmd_byte_addr;
 // Write Signals
 wire [15:0] c3_p0_wr_mask;
 wire [127:0]c3_p0_wr_data;
 wire [6:0]  c3_p0_wr_count;
 wire [15:0] c1_p0_wr_mask;
 wire [127:0]c1_p0_wr_data;
 wire [6:0]  c1_p0_wr_count;
 // Read Signals
 wire [127:0]c3_p0_rd_data;
 wire [6:0]  c3_p0_rd_count;
 wire [127:0]c1_p0_rd_data;
 wire [6:0]  c1_p0_rd_count;
 
// Instantiation of memory
 mem u_mem (
   .c3_sys_clk        (c3_sys_clk),
   .c3_sys_rst_i      (c_sys_rst_i),

   .mcb3_dram_dq      (mcb3_dram_dq), 
   .mcb3_dram_a       (mcb3_dram_a), 
   .mcb3_dram_ba      (mcb3_dram_ba),
   .mcb3_dram_ras_n   (mcb3_dram_ras_n), 
   .mcb3_dram_cas_n   (mcb3_dram_cas_n), 
   .mcb3_dram_we_n    (mcb3_dram_we_n), 
   .mcb3_dram_odt     (mcb3_dram_odt),
   .mcb3_dram_cke     (mcb3_dram_cke), 
   .mcb3_dram_ck      (mcb3_dram_ck), 
   .mcb3_dram_ck_n    (mcb3_dram_ck_n), 
   .mcb3_dram_dqs     (mcb3_dram_dqs), 
   .mcb3_dram_dqs_n   (mcb3_dram_dqs_n),
   .mcb3_dram_udqs    (mcb3_dram_udqs),   // for X16 parts 
   .mcb3_dram_udqs_n  (mcb3_dram_udqs_n), // for X16 parts
   .mcb3_dram_udm     (mcb3_dram_udm), // for X16 parts
   .mcb3_dram_dm      (mcb3_dram_dm),
   .mcb3_dram_reset_n (mcb3_dram_reset_n),
   .c3_clk0           (c3_clk0),
   .c3_rst0           (c3_rst0),
   .c3_calib_done     (led3_calib),
   .mcb3_rzq          (mcb3_rzq), 
   .mcb3_zio          (mcb3_zio),
   .c3_p0_cmd_clk     (c3_p0_cmd_clk),
   .c3_p0_cmd_en      (c3_p0_cmd_en),
   .c3_p0_cmd_instr   (c3_p0_cmd_instr),
   .c3_p0_cmd_bl      (c3_p0_cmd_bl),
   .c3_p0_cmd_byte_addr(c3_p0_cmd_byte_addr),
   .c3_p0_cmd_empty   (c3_p0_cmd_empty),
   .c3_p0_cmd_full    (c3_p0_cmd_full),
   .c3_p0_wr_clk      (c3_p0_wr_clk),
   .c3_p0_wr_en       (c3_p0_wr_en),
   .c3_p0_wr_mask     (c3_p0_wr_mask),
   .c3_p0_wr_data     (c3_p0_wr_data),
   .c3_p0_wr_full     (c3_p0_wr_full),
   .c3_p0_wr_empty    (c3_p0_wr_empty),
   .c3_p0_wr_count    (c3_p0_wr_count),
   .c3_p0_wr_underrun (c3_p0_wr_underrun),
   .c3_p0_wr_error    (c3_p0_wr_error),
   .c3_p0_rd_clk      (c3_p0_rd_clk),
   .c3_p0_rd_en       (c3_p0_rd_en),
   .c3_p0_rd_data     (c3_p0_rd_data),
   .c3_p0_rd_full     (c3_p0_rd_full),
   .c3_p0_rd_empty    (c3_p0_rd_empty),
   .c3_p0_rd_count    (c3_p0_rd_count),
   .c3_p0_rd_overflow (c3_p0_rd_overflow),
   .c3_p0_rd_error    (c3_p0_rd_error),
 
   .c1_sys_clk        (c1_sys_clk),
   .c1_sys_rst_i      (c_sys_rst_i),

   .mcb1_dram_dq      (mcb1_dram_dq), 
   .mcb1_dram_a       (mcb1_dram_a), 
   .mcb1_dram_ba      (mcb1_dram_ba),
   .mcb1_dram_ras_n   (mcb1_dram_ras_n), 
   .mcb1_dram_cas_n   (mcb1_dram_cas_n), 
   .mcb1_dram_we_n    (mcb1_dram_we_n), 
   .mcb1_dram_odt     (mcb1_dram_odt),
   .mcb1_dram_cke     (mcb1_dram_cke), 
   .mcb1_dram_ck      (mcb1_dram_ck), 
   .mcb1_dram_ck_n    (mcb1_dram_ck_n), 
   .mcb1_dram_dqs     (mcb1_dram_dqs), 
   .mcb1_dram_dqs_n   (mcb1_dram_dqs_n),
   .mcb1_dram_udqs    (mcb1_dram_udqs), // for X16 parts 
   .mcb1_dram_udqs_n  (mcb1_dram_udqs_n), // for X16 parts
   .mcb1_dram_udm     (mcb1_dram_udm), // for X16 parts
   .mcb1_dram_dm      (mcb1_dram_dm),
   .mcb1_dram_reset_n (mcb1_dram_reset_n),
   .c1_clk0           (c1_clk0),
   .c1_rst0           (c1_rst0),
   .c1_calib_done     (led1_calib),
   .mcb1_rzq          (mcb1_rzq), 
   .mcb1_zio          (mcb1_zio),
   .c1_p0_cmd_clk     (c1_p0_cmd_clk),
   .c1_p0_cmd_en      (c1_p0_cmd_en),
   .c1_p0_cmd_instr   (c1_p0_cmd_instr),
   .c1_p0_cmd_bl      (c1_p0_cmd_bl),
   .c1_p0_cmd_byte_addr (c1_p0_cmd_byte_addr),
   .c1_p0_cmd_empty   (c1_p0_cmd_empty),
   .c1_p0_cmd_full    (c1_p0_cmd_full),
   .c1_p0_wr_clk      (c1_p0_wr_clk),
   .c1_p0_wr_en       (c1_p0_wr_en),
   .c1_p0_wr_mask     (c1_p0_wr_mask),
   .c1_p0_wr_data     (c1_p0_wr_data),
   .c1_p0_wr_full     (c1_p0_wr_full),
   .c1_p0_wr_empty    (c1_p0_wr_empty),
   .c1_p0_wr_count    (c1_p0_wr_count),
   .c1_p0_wr_underrun (c1_p0_wr_underrun),
   .c1_p0_wr_error    (c1_p0_wr_error),
   .c1_p0_rd_clk      (c1_p0_rd_clk),
   .c1_p0_rd_en       (c1_p0_rd_en),
   .c1_p0_rd_data     (c1_p0_rd_data),
   .c1_p0_rd_full     (c1_p0_rd_full),
   .c1_p0_rd_empty    (c1_p0_rd_empty),
   .c1_p0_rd_count    (c1_p0_rd_count),
   .c1_p0_rd_overflow (c1_p0_rd_overflow),
   .c1_p0_rd_error    (c1_p0_rd_error)
 );

// Uer Interface instantiation for Bank1 DDR3 
galatea_ui ui_c1 (
   .c_clk0            (c1_clk0),
   .c_rst0            (c1_rst0),
   .c_p0_cmd_clk      (c1_p0_cmd_clk),
   .c_p0_cmd_en       (c1_p0_cmd_en),
   .c_p0_cmd_instr    (c1_p0_cmd_instr),
   .c_p0_cmd_bl       (c1_p0_cmd_bl),
   .c_p0_cmd_byte_addr(c1_p0_cmd_byte_addr),
   .c_p0_cmd_empty    (c1_p0_cmd_empty),
   .c_p0_cmd_full     (c1_p0_cmd_full),
   .c_p0_wr_clk       (c1_p0_wr_clk),
   .c_p0_wr_en        (c1_p0_wr_en),
   .c_p0_wr_mask      (c1_p0_wr_mask),
   .c_p0_wr_data      (c1_p0_wr_data),
   .c_p0_wr_full      (c1_p0_wr_full),
   .c_p0_wr_empty     (c1_p0_wr_empty),
   .c_p0_wr_count     (c1_p0_wr_count),
   .c_p0_wr_underrun  (c1_p0_wr_underrun),
   .c_p0_wr_error     (c1_p0_wr_error),
   .c_p0_rd_clk       (c1_p0_rd_clk),
   .c_p0_rd_en        (c1_p0_rd_en),
   .c_p0_rd_data      (c1_p0_rd_data),
   .c_p0_rd_full      (c1_p0_rd_full),
   .c_p0_rd_empty     (c1_p0_rd_empty),
   .c_p0_rd_count     (c1_p0_rd_count),
   .c_p0_rd_overflow  (c1_p0_rd_overflow),
   .c_p0_rd_error     (c1_p0_rd_error),
   .led_calib         (led1_calib),
   .led_pass          (led1_pass),
   .led_fail          (led1_fail)
   ); 
 
// Uer Interface instantiation for Bank3 DDR3 
galatea_ui ui_c3 (
   .c_clk0            (c3_clk0),
   .c_rst0            (c3_rst0),
   .c_p0_cmd_clk      (c3_p0_cmd_clk),
   .c_p0_cmd_en       (c3_p0_cmd_en),
   .c_p0_cmd_instr    (c3_p0_cmd_instr),
   .c_p0_cmd_bl       (c3_p0_cmd_bl),
   .c_p0_cmd_byte_addr(c3_p0_cmd_byte_addr),
   .c_p0_cmd_empty    (c3_p0_cmd_empty),
   .c_p0_cmd_full     (c3_p0_cmd_full),
   .c_p0_wr_clk       (c3_p0_wr_clk),
   .c_p0_wr_en        (c3_p0_wr_en),
   .c_p0_wr_mask      (c3_p0_wr_mask),
   .c_p0_wr_data      (c3_p0_wr_data),
   .c_p0_wr_full      (c3_p0_wr_full),
   .c_p0_wr_empty     (c3_p0_wr_empty),
   .c_p0_wr_count     (c3_p0_wr_count),
   .c_p0_wr_underrun  (c3_p0_wr_underrun),
   .c_p0_wr_error     (c3_p0_wr_error),
   .c_p0_rd_clk       (c3_p0_rd_clk),
   .c_p0_rd_en        (c3_p0_rd_en),
   .c_p0_rd_data      (c3_p0_rd_data),
   .c_p0_rd_full      (c3_p0_rd_full),
   .c_p0_rd_empty     (c3_p0_rd_empty),
   .c_p0_rd_count     (c3_p0_rd_count),
   .c_p0_rd_overflow  (c3_p0_rd_overflow),
   .c_p0_rd_error     (c3_p0_rd_error),
   .led_calib         (led3_calib),
   .led_pass          (led3_pass),
   .led_fail          (led3_fail)
   );
endmodule //galatea_ddr3

Create a Verilog file with .v extension and copy paste the following code in “galatea_ui.v”

In the following RTL code, a simple FSM is implemented with six states. The six states are IDLE, WR_CMD, WRITE, RD_CMD, READ and PARK.

Initially, the state machine is in the IDLE state. In this state, the FSM waits for the calibration (led_calib) to complete. Once the calibration completes, the state machine changes to WR_CMD state.

In WR_CMD state, the state machine waits for the MIG controller to be ready to accept new commands  by checking whether the signal c_p0_cmd_full is deasserted. Once the controller is ready to accept the command, the state machine writes the command to the controller and changes its state to WRITE.

In WRITE state, the FSM de-asserts the command enable and waits for the controller to be ready to accept data to be written to DDR3 by checking whether c_p0_wr_full signal is de-asserted. Once c_p0_wr_full signal is de-asserted, the MIG controller is ready to accept new data to be written to DDR3. The state machine asserts the write enable (c_p0_wr_en) and writes a fixed data (stored in data_to_write register) to controller’s write FIFO. The machine proceeds to RD_CMD state to read back the data from memory.

In RD_CMD state, the state machine waits for the MIG controller to be ready to accept new commands  by checking whether the signal c_p0_cmd_full is deasserted, similar to as in WR_CMD state. Whenever the MIG de-asserts the c_p0_cmd_full signal, it is ready to accept the read command. The state machine de-asserts the write enable signal (c_p0_wr_en), writes the “read” command to the MIG IP and changes its state to READ state.

In READ state, the FSM de-asserts the command enable (c_p0_cmd_en) and waits for the read empty signal (c_p0_rd_empty) from MIG to go low. Once the read empty signal gets de-asserted by MIG, the state machine captures data from MIG’s FIFO to data_read_from_memory register and changes its state to PARK.

The PARK state is used to compare the data written to the memory with the data read back from memory. If both match, then led_pass goes HIGH otherwise led_fail goes HIGH.

////////////////////////////////////////////////////////////////////////////
// File Name: galatea_ui
// Description: Simple FSM to write data to memory and read back from it
////////////////////////////////////////////////////////////////////////////
module galatea_ui( 
 input   c_clk0,
 input   c_rst0,
 // Command Signals
 output  c_p0_cmd_clk,
 output  reg c_p0_cmd_en,
 output  reg [2:0]  c_p0_cmd_instr,
 output  reg [5:0]  c_p0_cmd_bl,
 output  reg [29:0] c_p0_cmd_byte_addr,
 input   c_p0_cmd_empty,
 input   c_p0_cmd_full,
 // Write Signals
 output  c_p0_wr_clk,
 output  reg c_p0_wr_en,
 output  [15:0] c_p0_wr_mask,
 output  reg [127:0]c_p0_wr_data,
 input   c_p0_wr_full,
 input   c_p0_wr_empty,
 input   [6:0] c_p0_wr_count,
 input   c_p0_wr_underrun,
 input   c_p0_wr_error,
 // Read Signals
 output  c_p0_rd_clk,
 output  reg c_p0_rd_en,
 input   [127:0]c_p0_rd_data,
 input   c_p0_rd_full,
 input   c_p0_rd_empty,
 input   [6:0]  c_p0_rd_count,
 input   c_p0_rd_overflow,
 input   c_p0_rd_error,
 input   led_calib,
 output  reg led_pass,
 output  reg led_fail
 );

reg  [2:0]  state;
reg  [127:0]data_read_from_memory = 128'd0;
wire [127:0]data_to_write = {32'hcafebabe, 32'h12345678,
                             32'hAA55AA55, 32'h55AA55AA}; 
 
assign c_p0_cmd_clk = c_clk0;
assign c_p0_wr_clk  = c_clk0;
assign c_p0_rd_clk  = c_clk0;

localparam IDLE   = 3'h0,
           WR_CMD = 3'h1,
           WRITE  = 3'h2,
           RD_CMD = 3'h3,
           READ   = 3'h4,
           PARK   = 3'h5; 
assign c_p0_wr_mask = 16'h0000;
//****************** State Machine start here ****************************//
always@(posedge c_clk0)
begin
  if(c_rst0) begin
    c_p0_cmd_byte_addr <= 0;
    c_p0_cmd_bl   <= 1; 
    state         <= IDLE;
    c_p0_cmd_instr<= 3'b000;
    c_p0_cmd_en   <= 1'b0;
    c_p0_wr_en    <= 1'b0;
    c_p0_rd_en    <= 1'b0;
    led_pass      <= 1'b0;
    led_fail      <= 1'b0;
   end
   else begin
     case(state)
       IDLE : begin
         if(led_calib) begin
           state <= WR_CMD;
         end
       end
 
       WR_CMD : begin
         if(~c_p0_cmd_full) begin
           c_p0_cmd_byte_addr <= 0;
           c_p0_cmd_bl    <= 1;
           c_p0_cmd_instr <= 3'b000;
           c_p0_cmd_en    <= 1'b1;
           state          <= WRITE;
          end
       end
 
       WRITE : begin
         c_p0_cmd_en    <= 1'b0; 
         if(~c_p0_wr_full) begin
           c_p0_wr_en   <= 1'b1;
           c_p0_wr_data <= data_to_write;
           state        <= RD_CMD;
         end
       end
 
       RD_CMD : begin
         if(~c_p0_cmd_full) begin
           c_p0_wr_en     <= 1'b0;
           c_p0_cmd_byte_addr <= 0;
           c_p0_cmd_bl    <= 1;
           c_p0_cmd_instr <= 3'b001;
           c_p0_cmd_en    <= 1'b1; 
           state          <= READ;
         end
       end
 
       READ : begin
         c_p0_cmd_en  <= 1'b0;
         if(~c_p0_rd_empty) begin
           c_p0_rd_en <= 1'b1;
           data_read_from_memory <= c_p0_rd_data;
           state      <= PARK;
         end
       end
 
       PARK : begin
         c_p0_rd_en <= 1'b0;
         if (data_to_write == data_read_from_memory) begin
           led_pass <= 1;
         end else if (data_to_write != data_read_from_memory) begin
           led_fail <= 1;
         end
       end
 
       default: state <= IDLE;
     endcase
   end
end
endmodule

Step 6:

Create a constraints file and copy-paste the following constraints.

CONFIG VCCAUX = "3.3" ;

NET "c3_sys_clk"  LOC = G9  | IOSTANDARD = LVCMOS33 | PERIOD = 100MHz;
NET "c1_sys_clk"  LOC = Y13 | IOSTANDARD = LVCMOS33 | PERIOD = 100MHz;
NET "c_sys_rst_i" LOC = G11 | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = FAST | PULLDOWN;

NET "led3_fail"   LOC = B18 | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = FAST;
NET "led3_pass"   LOC = D19 | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = FAST;
NET "led3_calib"  LOC = D18 | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = FAST;

NET "led1_fail"   LOC = A19 | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = FAST;
NET "led1_pass"   LOC = C19 | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = FAST;
NET "led1_calib"  LOC = A18 | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = FAST;

NET "mcb3_dram_a[0]"    LOC = "K2" | IOSTANDARD = SSTL15_II;
NET "mcb3_dram_a[1]"    LOC = "K1" | IOSTANDARD = SSTL15_II;
NET "mcb3_dram_a[2]"    LOC = "K5" | IOSTANDARD = SSTL15_II;
NET "mcb3_dram_a[3]"    LOC = "M6" | IOSTANDARD = SSTL15_II;
NET "mcb3_dram_a[4]"    LOC = "H3" | IOSTANDARD = SSTL15_II;
NET "mcb3_dram_a[5]"    LOC = "M3" | IOSTANDARD = SSTL15_II;
NET "mcb3_dram_a[6]"    LOC = "L4" | IOSTANDARD = SSTL15_II;
NET "mcb3_dram_a[7]"    LOC = "K6" | IOSTANDARD = SSTL15_II;
NET "mcb3_dram_a[8]"    LOC = "G3" | IOSTANDARD = SSTL15_II;
NET "mcb3_dram_a[9]"    LOC = "G1" | IOSTANDARD = SSTL15_II;
NET "mcb3_dram_a[10]"   LOC = "J4" | IOSTANDARD = SSTL15_II;
NET "mcb3_dram_a[11]"   LOC = "E1" | IOSTANDARD = SSTL15_II;
NET "mcb3_dram_a[12]"   LOC = "F1" | IOSTANDARD = SSTL15_II;
NET "mcb3_dram_a[13]"   LOC = "J6" | IOSTANDARD = SSTL15_II;

NET "mcb3_dram_dq[0]"   LOC = "R3" | IOSTANDARD = SSTL15_II;
NET "mcb3_dram_dq[1]"   LOC = "R1" | IOSTANDARD = SSTL15_II;
NET "mcb3_dram_dq[2]"   LOC = "P2" | IOSTANDARD = SSTL15_II;
NET "mcb3_dram_dq[3]"   LOC = "P1" | IOSTANDARD = SSTL15_II;
NET "mcb3_dram_dq[4]"   LOC = "L3" | IOSTANDARD = SSTL15_II;
NET "mcb3_dram_dq[5]"   LOC = "L1" | IOSTANDARD = SSTL15_II;
NET "mcb3_dram_dq[6]"   LOC = "M2" | IOSTANDARD = SSTL15_II;
NET "mcb3_dram_dq[7]"   LOC = "M1" | IOSTANDARD = SSTL15_II;
NET "mcb3_dram_dq[8]"   LOC = "T2" | IOSTANDARD = SSTL15_II;
NET "mcb3_dram_dq[9]"   LOC = "T1" | IOSTANDARD = SSTL15_II;
NET "mcb3_dram_dq[10]"  LOC = "U3" | IOSTANDARD = SSTL15_II;
NET "mcb3_dram_dq[11]"  LOC = "U1" | IOSTANDARD = SSTL15_II;
NET "mcb3_dram_dq[12]"  LOC = "W3" | IOSTANDARD = SSTL15_II;
NET "mcb3_dram_dq[13]"  LOC = "W1" | IOSTANDARD = SSTL15_II;
NET "mcb3_dram_dq[14]"  LOC = "Y2" | IOSTANDARD = SSTL15_II;
NET "mcb3_dram_dq[15]"  LOC = "Y1" | IOSTANDARD = SSTL15_II;

NET "mcb3_dram_ba[0]"   LOC = "J3" | IOSTANDARD = SSTL15_II;
NET "mcb3_dram_ba[1]"   LOC = "J1" | IOSTANDARD = SSTL15_II;
NET "mcb3_dram_ba[2]"   LOC = "H1" | IOSTANDARD = SSTL15_II;
NET "mcb3_dram_ras_n"   LOC = "M5" | IOSTANDARD = SSTL15_II;
NET "mcb3_dram_cas_n"   LOC = "M4" | IOSTANDARD = SSTL15_II;
NET "mcb3_dram_we_n"    LOC = "H2" | IOSTANDARD = SSTL15_II;
NET "mcb3_dram_ck"      LOC = "K4" | IOSTANDARD = DIFF_SSTL15_II; 
NET "mcb3_dram_ck_n"    LOC = "K3" | IOSTANDARD = DIFF_SSTL15_II;
NET "mcb3_dram_cke"     LOC = "F2" | IOSTANDARD = SSTL15_II;
NET "mcb3_dram_dm"      LOC = "N4" | IOSTANDARD = SSTL15_II;
NET "mcb3_dram_dqs"     LOC = "N3" | IOSTANDARD = DIFF_SSTL15_II;
NET "mcb3_dram_dqs_n"   LOC = "N1" | IOSTANDARD = DIFF_SSTL15_II;
NET "mcb3_dram_udqs"    LOC = "V2" | IOSTANDARD = DIFF_SSTL15_II;
NET "mcb3_dram_udqs_n"  LOC = "V1" | IOSTANDARD = DIFF_SSTL15_II;
NET "mcb3_dram_udm"     LOC = "P3" | IOSTANDARD = SSTL15_II;
NET "mcb3_dram_odt"     LOC = "L6" | IOSTANDARD = SSTL15_II;
NET "mcb3_dram_reset_n" LOC = "E3" | IOSTANDARD = LVCMOS15;
NET "mcb3_zio" IOSTANDARD = SSTL15_II;
NET "mcb3_rzq" IOSTANDARD = SSTL15_II;

NET "mcb1_dram_a[0]"    LOC = "H21" | IOSTANDARD = SSTL15_II;
NET "mcb1_dram_a[1]"    LOC = "H22" | IOSTANDARD = SSTL15_II;
NET "mcb1_dram_a[2]"    LOC = "G22" | IOSTANDARD = SSTL15_II;
NET "mcb1_dram_a[3]"    LOC = "J20" | IOSTANDARD = SSTL15_II;
NET "mcb1_dram_a[4]"    LOC = "H20" | IOSTANDARD = SSTL15_II;
NET "mcb1_dram_a[5]"    LOC = "M20" | IOSTANDARD = SSTL15_II;
NET "mcb1_dram_a[6]"    LOC = "M19" | IOSTANDARD = SSTL15_II;
NET "mcb1_dram_a[7]"    LOC = "G20" | IOSTANDARD = SSTL15_II;
NET "mcb1_dram_a[8]"    LOC = "E20" | IOSTANDARD = SSTL15_II;
NET "mcb1_dram_a[9]"    LOC = "E22" | IOSTANDARD = SSTL15_II;
NET "mcb1_dram_a[10]"   LOC = "J19" | IOSTANDARD = SSTL15_II;
NET "mcb1_dram_a[11]"   LOC = "H19" | IOSTANDARD = SSTL15_II;
NET "mcb1_dram_a[12]"   LOC = "F22" | IOSTANDARD = SSTL15_II;
NET "mcb1_dram_a[13]"   LOC = "G19" | IOSTANDARD = SSTL15_II;

NET "mcb1_dram_dq[0]"   LOC = "R20" | IOSTANDARD = SSTL15_II;
NET "mcb1_dram_dq[1]"   LOC = "R22" | IOSTANDARD = SSTL15_II;
NET "mcb1_dram_dq[2]"   LOC = "P21" | IOSTANDARD = SSTL15_II;
NET "mcb1_dram_dq[3]"   LOC = "P22" | IOSTANDARD = SSTL15_II;
NET "mcb1_dram_dq[4]"   LOC = "L20" | IOSTANDARD = SSTL15_II;
NET "mcb1_dram_dq[5]"   LOC = "L22" | IOSTANDARD = SSTL15_II;
NET "mcb1_dram_dq[6]"   LOC = "M21" | IOSTANDARD = SSTL15_II;
NET "mcb1_dram_dq[7]"   LOC = "M22" | IOSTANDARD = SSTL15_II;
NET "mcb1_dram_dq[8]"   LOC = "T21" | IOSTANDARD = SSTL15_II;
NET "mcb1_dram_dq[9]"   LOC = "T22" | IOSTANDARD = SSTL15_II;
NET "mcb1_dram_dq[10]"  LOC = "U20" | IOSTANDARD = SSTL15_II;
NET "mcb1_dram_dq[11]"  LOC = "U22" | IOSTANDARD = SSTL15_II;
NET "mcb1_dram_dq[12]"  LOC = "W20" | IOSTANDARD = SSTL15_II;
NET "mcb1_dram_dq[13]"  LOC = "W22" | IOSTANDARD = SSTL15_II;
NET "mcb1_dram_dq[14]"  LOC = "Y21" | IOSTANDARD = SSTL15_II;
NET "mcb1_dram_dq[15]"  LOC = "Y22" | IOSTANDARD = SSTL15_II;

NET "mcb1_dram_ba[0]"   LOC = "K17" | IOSTANDARD = SSTL15_II;
NET "mcb1_dram_ba[1]"   LOC = "L17" | IOSTANDARD = SSTL15_II;
NET "mcb1_dram_ba[2]"   LOC = "K18" | IOSTANDARD = SSTL15_II;
NET "mcb1_dram_ras_n"   LOC = "K21" | IOSTANDARD = SSTL15_II;
NET "mcb1_dram_cas_n"   LOC = "K22" | IOSTANDARD = SSTL15_II;
NET "mcb1_dram_we_n"    LOC = "K19" | IOSTANDARD = SSTL15_II;
NET "mcb1_dram_ck"      LOC = "K20" | IOSTANDARD = DIFF_SSTL15_II; 
NET "mcb1_dram_ck_n"    LOC = "L19" | IOSTANDARD = DIFF_SSTL15_II;
NET "mcb1_dram_cke"     LOC = "F21" | IOSTANDARD = SSTL15_II;
NET "mcb1_dram_dm"      LOC = "N19" | IOSTANDARD = SSTL15_II;
NET "mcb1_dram_dqs"     LOC = "N20" | IOSTANDARD = DIFF_SSTL15_II;
NET "mcb1_dram_dqs_n"   LOC = "N22" | IOSTANDARD = DIFF_SSTL15_II;
NET "mcb1_dram_udqs"    LOC = "V21" | IOSTANDARD = DIFF_SSTL15_II;
NET "mcb1_dram_udqs_n"  LOC = "V22" | IOSTANDARD = DIFF_SSTL15_II;
NET "mcb1_dram_udm"     LOC = "P20" | IOSTANDARD = SSTL15_II;
NET "mcb1_dram_odt"     LOC = "J22" | IOSTANDARD = SSTL15_II;
NET "mcb1_dram_reset_n" LOC = "H18" | IOSTANDARD = LVCMOS15;
NET "mcb1_zio" IOSTANDARD = SSTL15_II;
NET "mcb1_rzq" IOSTANDARD = SSTL15_II;

Step 7:

Generate Bitstream by clicking on “Generate Bitstream”. Once the Bitstream is generated successfully, power up Galatea and program it using Xilinx Platform Cable USB II.

FPGA pins A18C19 and A19 are connected to led_calib1led_pass1 and led_fail1 signals respectively, corresponding to controller C1 for DRR3 on Bank 1. FPGA pins D18, D19 and B18 are connected to led_calib3, led_pass3 and led_fail3 respectively, corresponding to controller C3 for DRR3 on Bank 3. After programming make sure that led_calib1 and led_calib3 (calibration done) signals go HIGH indicating that initial calibration completed successfully for both DDR3 memories which are available on Bank 1 and Bank 3 of the FPGA. Also, led_pass1 and led_pass3 should go HIGH indicating that data written to memory and read back successfully and led_fail1 and led_fail3 should stay LOW since led_fail1 and led_fail3 being HIGH indicates failed attempt to write to and read data from memory.

You can use either LED and resistor or Multimeter to measure the output of these signals. If you observe led_calib1, led_calib3, led_pass1 and led_pass3 LEDs high and led_fail1and led_fail3 LEDs stay low, then your Galatea PCI Express Spartan 6 DDR3 example design worked. Congratulations!

Was this helpful?

Leave A Comment
*
*