// =============================================================================
//                           COPYRIGHT NOTICE
// Copyright 2004 (c) Lattice Semiconductor Corporation
// ALL RIGHTS RESERVED
// This confidential and proprietary software may be used only as authorised by
// a licensing agreement from Lattice Semiconductor Corporation.
// The entire notice above must be reproduced on all authorized copies and
// copies may only be made to the extent permitted by a licensing agreement from
// Lattice Semiconductor Corporation.
//
// Lattice Semiconductor Corporation        TEL : 1-800-Lattice (USA and Canada)
// 5555 NE Moore Court                            408-826-6000 (other locations)
// Hillsboro, OR 97124                     web  : http://www.latticesemi.com/
// U.S.A                                   email: techsupport@latticesemi.com
// =============================================================================/
//                        FILE DETAILS
// Project          : DDR SDRAM Controller
// File             : albuf.v
// Title            : Data/Datavalid alignment logic
// Description      : This module generates the datavalid as well as the pio_read signal
// =============================================================================
//                        REVISION HISTORY
// Version          : 1.0
// Mod. Date        : Sep 08, 2004
// Changes Made     : Initial Creation
//
// =============================================================================

`timescale 1ns/100ps

module albuf (

    // Clock and reset
    clk,
    rst_n,

    // Input signals 
    datain,       
    datavalid_in,  
    read_command,
    cas_latency,
    data_valid_tap,

    // Output signals 
    dataout,    
    pio_read_dly,
    pio_read_early,
    datavalid_out

);

//////////////////////////////////////////////////////////////////////////////
// Input signals
input                                 clk;
input                                 rst_n;
input                                 read_command;
input  [2:0]                          cas_latency;
input  [1:0]                          data_valid_tap;
input                                 datavalid_in;
input  [`DSIZE-1:0]                   datain;

// Output signals to the FPGA Logic
output [`DSIZE-1:0]                   dataout;
output                                datavalid_out;
output                                pio_read_dly;
output                                pio_read_early;

///////////////////////////////////////////////////////////////////////////
parameter CL_1_5 = 3'b101;
parameter CL_2_0 = 3'b010;
parameter CL_2_5 = 3'b110;
parameter CL_3_0 = 3'b011;
///////////////////////////////////////////////////////////////////////////

// Internal registers and wires

reg       [`DSIZE-1:0]               dataout;
reg       [`DSIZE-1:0]               datain_d;
reg       [`DSIZE-1:0]               datain_2d;
reg                                  datavalid_out;
reg                                  int_datavalid_out;
reg                                  int_datavalid_out_d;
reg                                  int_datavalid_out_2d;

wire      [3:0]                      delay_cnt;

reg                                  read_command_d;    // Delayed RD cmd
reg                                  read_command_2d;   // Delayed RD cmd
reg                                  read_command_3d;   // Delayed RD cmd
reg                                  read_command_4d;   // Delayed RD cmd
reg                                  read_command_5d;   // Delayed RD cmd
reg                                  read_command_6d;   // Delayed RD cmd
reg                                  read_command_7d;   // Delayed RD cmd


reg                                  datavalid_in_d;    // Delayed datavalid_in 
reg                                  datavalid_in_d2;   // Delayed datavalid_in;
reg                                  dvt_after_cas;     // Data valid tmp after cas latency
reg                                  dv_ac_d;           // delayed dv_after_cas
reg                                  dv_ac_d2;          // delayed dv_ac_d
reg                                  dv_ac_d3;          // delayed dv_ac_d
reg                                  dv_ac_d4;          // delayed dv_ac_d
reg                                  dv_ac_d5;          // delayed dv_ac_d

reg                                  pio_read_dly;
reg                                  pio_read_early;
///////////////////////////////////////////////////////////////////////////
// Data Valid Logic 
// ----------------
// This will match the data valid to the user to the data presented
// to the user. The received data valid from the core will be delayed
// by the cas latency and then delayed further by 3 clock cycles to 
// compensate the delay on the data by the I/O logic and the alignment
// logic.  
///////////////////////////////////////////////////////////////////////////

// Delay the incoming data valid tmp signal and then select 
// cas latency delayed signal 
always @ (posedge clk or negedge rst_n) begin
   if (!rst_n) begin
      datavalid_in_d         <= 1'b0;
      datavalid_in_d2        <= 1'b0;
   end
   else begin
      datavalid_in_d         <= datavalid_in;
      datavalid_in_d2        <= datavalid_in_d;
   end
end

// Get the data valid tmp [dvt] after delaying it for 
// the cas delay
always @ (negedge rst_n or posedge clk) begin
   if (!rst_n) begin
      dvt_after_cas     <= 1'b0;  
   end 
   else begin
      case (cas_latency)
         CL_1_5: begin
            dvt_after_cas <= datavalid_in;
         end
         CL_2_0: begin
            dvt_after_cas <= datavalid_in_d;
         end
         CL_2_5: begin
            dvt_after_cas <= datavalid_in_d;
         end
         CL_3_0: begin
            dvt_after_cas <= datavalid_in_d2;
         end
         default: begin
            dvt_after_cas <= 1'b0;
         end
      endcase
   end
end


// Delay the data valid after cas latency delay signal
always @ (posedge clk or negedge rst_n) begin
   if (!rst_n) begin
      dv_ac_d           <= 1'b0;
      dv_ac_d2          <= 1'b0;
      dv_ac_d3          <= 1'b0;
      dv_ac_d4          <= 1'b0;
      dv_ac_d5          <= 1'b0;
   end
   else begin
      dv_ac_d           <= dvt_after_cas;
      dv_ac_d2          <= dv_ac_d;
      dv_ac_d3          <= dv_ac_d2;
      dv_ac_d4          <= dv_ac_d3;
      dv_ac_d5          <= dv_ac_d4;
   end
end


// Based on the data_valid_tap setting delay the data_valid going out
// Min delay is 3 clock cycles for data_valid_tap = 0
always @ (negedge rst_n or posedge clk) begin
   if (!rst_n) begin
      int_datavalid_out            <= 1'b0;  
      int_datavalid_out_d          <= 1'b0;
      int_datavalid_out_2d         <= 1'b0;
      datavalid_out                <= 1'b0;
   end 
   else begin
      case(data_valid_tap)
         2'b00: int_datavalid_out  <= dv_ac_d2;
         2'b01: int_datavalid_out  <= dv_ac_d3;
         2'b10: int_datavalid_out  <= dv_ac_d4;
         2'b11: int_datavalid_out  <= dv_ac_d5;
      endcase

       int_datavalid_out_d         <= int_datavalid_out;
       int_datavalid_out_2d        <= int_datavalid_out_d;

       datavalid_out <= int_datavalid_out_2d;
   end
end

////////////////////////////////////////////////////////////////////////

assign delay_cnt = {cas_latency + data_valid_tap + 1};

always @ (posedge clk or negedge rst_n) begin
    if (!rst_n) begin
       read_command_d <= 'd0;
       read_command_2d <= 'd0;
       read_command_3d <= 'd0;
       read_command_4d <= 'd0;
       read_command_5d <= 'd0;
       read_command_6d <= 'd0;
       read_command_7d <= 'd0;

       pio_read_dly    <= 1'b0;
       pio_read_early  <= 1'b0;
    end
    else begin
       read_command_d  <= read_command;
       read_command_2d <= read_command_d;
       read_command_3d <= read_command_2d;
       read_command_4d <= read_command_3d;
       read_command_5d <= read_command_4d;
       read_command_6d <= read_command_5d;
       read_command_7d <= read_command_6d;

       case(delay_cnt)
          'd3: begin
	      pio_read_dly   <= read_command_2d;
	      pio_read_early   <= read_command_d;
	   end

          'd4: begin
	      pio_read_dly   <= read_command_3d;
	      pio_read_early   <= read_command_2d;
	   end

          'd5: begin
	      pio_read_dly   <= read_command_4d;
	      pio_read_early   <= read_command_3d;
	   end

          'd6: begin
	      pio_read_dly   <= read_command_5d;
	      pio_read_early   <= read_command_4d;
	   end

          'd7: begin
	      pio_read_dly   <= read_command_6d;
	      pio_read_early   <= read_command_5d;
	   end
       endcase
    end
end
////////////////////////////////////////////////////////////////////////
// Flop the data and data valid signals comming in
always @ (posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        datain_d               <= {`DSIZE{1'b0}};
        datain_2d              <= {`DSIZE{1'b0}};
        dataout                <= {`DATA_WIDTH{1'b0}};
    end
    else begin
        datain_d               <= datain;
        datain_2d              <= datain_d;
        dataout                <= datain_2d;
    end
end

///////////////////////////////////////////////////////////////////////////
endmodule
