/*******************************************************************************
* 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