/******************************************************************************* * Module: cmd_addr * Date:2014-04-26 * Author: Andrey Filippov * Description: DDR3 command/address signals * * Copyright (c) 2014 Elphel, Inc. * cmd_addr.v 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. * * cmd_addr.v 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 . *******************************************************************************/ `timescale 1ns/1ps /* Currently ddr3_a, ddr3_ba, ddr_cke and ddr_odt do not change inside a 2-clock command cycle, so half register bits are removed during optimization */ module cmd_addr #( parameter IODELAY_GRP = "IODELAY_MEMORY", parameter IOSTANDARD = "SSTL15", parameter SLEW = "SLOW", parameter real REFCLK_FREQUENCY = 300.0, parameter HIGH_PERFORMANCE_MODE = "FALSE", parameter integer ADDRESS_NUMBER= 15 )( output [ADDRESS_NUMBER-1:0] ddr3_a, // output address ports (14:0) for 4Gb device output [2:0] ddr3_ba, // output bank address ports output ddr3_we, // output WE port output ddr3_ras, // output RAS port output ddr3_cas, // output CAS port output ddr3_cke, // output Clock Enable port output ddr3_odt, // output ODT port input clk, // free-running system clock, same frequency as iclk (shared for R/W) input clk_div, // free-running half clk frequency, front aligned to clk (shared for R/W) input rst, // reset delays/serdes input [2*ADDRESS_NUMBER-1:0] in_a, // input address, 2 bits per signal (first, second) (29:0) for 4Gb device input [5:0] in_ba, // input bank address, 2 bits per signal (first, second) input [1:0] in_we, // input WE, 2 bits (first, second) input [1:0] in_ras, // input RAS, 2 bits (first, second) input [1:0] in_cas, // input CAS, 2 bits (first, second) input [1:0] in_cke, // input CKE, 2 bits (first, second) input [1:0] in_odt, // input ODT, 2 bits (first, second) // input [1:0] in_tri, // tristate command/address outputs - same timing, but no odelay input in_tri, // tristate command/address outputs - same timing, but no odelay input [7:0] dly_data, // delay value (3 LSB - fine delay) input [4:0] dly_addr, // select which delay to program input ld_delay, // load delay data to selected iodelayl (clk_div synchronous) input set // clk_div synchronous set all delays from previously loaded values ); reg [2*ADDRESS_NUMBER-1:0] in_a_r=0; reg [5:0] in_ba_r=0; reg [1:0] in_we_r=2'h3, in_ras_r=2'h3, in_cas_r=2'h3, in_cke_r=2'h3, in_odt_r=2'h0; //reg [1:0] in_tri_r=2'h0; // or tri-state on reset? reg in_tri_r=1'b1; // or tri-state on reset? // Preventing register duplication (* keep = "true" *) reg [7:0] dly_data_r=0; (* keep = "true" *) reg set_r=0; reg [7:0] ld_dly_cmd=8'b0; reg [ADDRESS_NUMBER-1:0] ld_dly_addr=0; //wire [ADDRESS_NUMBER-1:0] decode_addr; wire [23:0] decode_addr24; wire [7:0] decode_sel={ (dly_addr[2:0]==7)?1'b1:1'b0, (dly_addr[2:0]==6)?1'b1:1'b0, (dly_addr[2:0]==5)?1'b1:1'b0, (dly_addr[2:0]==4)?1'b1:1'b0, (dly_addr[2:0]==3)?1'b1:1'b0, (dly_addr[2:0]==2)?1'b1:1'b0, (dly_addr[2:0]==1)?1'b1:1'b0, (dly_addr[2:0]==0)?1'b1:1'b0}; assign decode_addr24={ (dly_addr[4:3] == 2'h2)?decode_sel[7:0]:8'h0, (dly_addr[4:3] == 2'h1)?decode_sel[7:0]:8'h0, (dly_addr[4:3] == 2'h0)?decode_sel[7:0]:8'h0}; always @ (posedge clk_div or posedge rst) begin if (rst) begin in_a_r <= 0; in_ba_r <= 6'b0; in_we_r <= 2'h3; in_ras_r <= 2'h3; in_cas_r <= 2'h3; in_cke_r <= 2'h3; in_odt_r <= 2'h0; // in_tri_r <= 2'h0; // or tri-state on reset? in_tri_r <= 1'b1; // or tri-state on reset? dly_data_r<=8'b0;set_r<=1'b0; ld_dly_cmd <= 8'b0; ld_dly_addr <= 0; end else begin in_a_r <= in_a; in_ba_r <= in_ba; in_we_r <= in_we; in_ras_r <= in_ras; in_cas_r <= in_cas; in_cke_r <= in_cke; in_odt_r <= in_odt; in_tri_r <= in_tri; dly_data_r<=dly_data; set_r<=set; ld_dly_cmd <= {8 { dly_addr[4] & dly_addr[3] & ld_delay}} & decode_sel[7:0]; // ld_dly_addr <= {(ADDRESS_NUMBER) {ld_delay}} & decode_addr; ld_dly_addr <= {(ADDRESS_NUMBER) {ld_delay}} & decode_addr24[ADDRESS_NUMBER-1:0]; end end // All addresses generate genvar i; for (i=0; i