OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [orpsocv2/] [boards/] [xilinx/] [ml501/] [rtl/] [verilog/] [xilinx_ssram/] [xilinx_ssram.v] - Rev 426

Go to most recent revision | Compare with Previous | Blame | View Log

//////////////////////////////////////////////////////////////////////
////                                                              ////
////  Xilinx ML501 SSRAM controller with Wishbone Interface       ////
////                                                              ////
////  Description                                                 ////
////  ZBT SSRAM controller for ML501 board part (or any ZBT RAM)  ////
////  Timing relies on definition of multi-cycle paths during     ////
////  synthesis.                                                  ////
////                                                              ////
////  To Do:                                                      ////
////                                                              ////
////  Author(s):                                                  ////
////      - Julius Baxter, julius.baxter@orsoc.se                 ////
////                                                              ////
////                                                              ////
//////////////////////////////////////////////////////////////////////
////                                                              ////
//// Copyright (C) 2010 Authors and OPENCORES.ORG                 ////
////                                                              ////
//// This source file may be used and distributed without         ////
//// restriction provided that this copyright statement is not    ////
//// removed from the file and that any derivative work contains  ////
//// the original copyright notice and the associated disclaimer. ////
////                                                              ////
//// This source file is free software; you can redistribute it   ////
//// and/or modify it under the terms of the GNU Lesser General   ////
//// Public License as published by the Free Software Foundation; ////
//// either version 2.1 of the License, or (at your option) any   ////
//// later version.                                               ////
////                                                              ////
//// This source 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 Lesser General Public License for more ////
//// details.                                                     ////
////                                                              ////
//// You should have received a copy of the GNU Lesser General    ////
//// Public License along with this source; if not, download it   ////
//// from http://www.opencores.org/lgpl.shtml                     ////
////                                                              ////
//////////////////////////////////////////////////////////////////////
/*
 * Controller for ZBT synchronous SRAM (ISSI IS61NLP25636A-200TQL)
 * Explicitly uses Xilinx primitives
 * Currently configured for a 1/4 ratio between bus/ssram clocks: 50 / 200 MHz
 * Requires declaration of some multi-cycle paths during synthesis.
 * 
 * Note: clk_200 and bus clock should be in phase (from same DCM)
 * 
 * Clocking/phase counting scheme (to change it to higher/lower ratio):
 * 
 * We run a phase counter, checking the bus on the last cycle before we hit another multiple of the SSRAM clock to the bus clock (so cycle 3 if ratio is 4, or a 50MHz system bus and 200MHz SRAM), this gives the system bus signals almost another whole cycle to reach our 200MHz regs (and where we define one of the multi-cycle paths). Once we have the stuff registered it's business as usual on the bus to the SRAM. Then we let it sit in our register for a clock or two
 */
module xilinx_ssram
  (
   // WB ports
    input [31:0]       wb_adr_i,
    input 	       wb_stb_i,
    input 	       wb_cyc_i,
    input 	       wb_we_i,
    input [3:0]        wb_sel_i,
    input [31:0]       wb_dat_i,
    output [31:0]      wb_dat_o,
    output	       wb_ack_o,
 
    input 	       wb_clk,
    input 	       wb_rst,
 
   // SSRAM interface
    input 	       clk_200,
    output wire	       sram_clk,
    input 	       sram_clk_fb,
    output reg [21:1]  sram_addr,
    inout [31:0]       sram_dq_io,
    output reg	       sram_ce_l,
    output reg	       sram_oe_l,    
    output reg	       sram_we_l,
    output reg [3:0]   sram_bw_l,
    output reg	       sram_adv_ld_l,
    output 	       sram_mode
 
   );
 
   wire [31:0] 	       sram_dq_i;
   reg [31:0] 	       sram_dq_o;
   reg 		       ssram_controller_oe_l;
 
   wire 	       dcm0_clk0_prebufg, dcm0_clk0;
   wire 	       dcm0_locked;
 
   wire 	       dcms_locked;
 
   reg 		       wb_clk_r = 1'b0;
   reg 		       wb_clk_r_d;
   wire 	       wb_clk_edge;
 
   reg 		       wb_ack_write;   
   reg [2:0] 	       wb_ack_read_shiftreg;   
 
   reg [2:0] 	       clk_200_phase;
   reg [4:0] 	       clk_200_cycle_counter;
 
   reg [31:0] 	       data_rd;
   wire [3:0] 	       we;
 
   reg 		       write_cycle;
   reg [3:0] 	       we_r;
   reg 		       reg_from_bus_domain, reg_from_bus_domain_r;
 
   assign dcms_locked = dcm0_locked;   
 
   assign we = wb_sel_i & {4{wb_cyc_i & wb_stb_i & wb_we_i}};
 
   assign sram_clk = dcm0_clk0;
 
   // Do wb_clk edge detection with this
   assign wb_clk_edge = wb_clk_r & ~wb_clk_r_d;
 
   assign sram_mode = 0;
 
   initial begin
      $display("* SSRAM controller instantiated at %m.");
   end
 
   // We ACK writes after one cycle
   always @(posedge wb_clk)
     wb_ack_write <= wb_cyc_i & wb_stb_i & wb_we_i & !wb_ack_write;
 
   // We ACK reads after 3
   always @(posedge wb_clk)
     wb_ack_read_shiftreg <= {wb_ack_read_shiftreg[1:0], wb_cyc_i & wb_stb_i & !wb_we_i & !(|wb_ack_read_shiftreg)};
 
   assign wb_ack_o = wb_we_i ? wb_ack_write : wb_ack_read_shiftreg[2];   
 
   // Push the bus clock through a register
   always @(posedge wb_clk) begin
      wb_clk_r <= ~wb_clk_r;
   end
 
   // Sample this with the 150 MHz clock
   always @(posedge clk_200) begin
      wb_clk_r_d <= wb_clk_r;      
   end
 
  // Maintain a phase count, it goes 0->7 (8 phases, to be clear)
  always @(posedge clk_200) begin
    if (wb_clk_edge) begin
      // Will be at 1 next cycle
      clk_200_phase <= 3'd1;
    end else if (clk_200_phase < 3'd7 & dcms_locked) begin
      clk_200_phase <= clk_200_phase + 1;
    end else begin
      clk_200_phase <= 3'd0;
    end
  end      
 
// Multicycle trickery
 
   // Reads will happen like this:
   // * Read address is given 3 clk_200 cycles to settle
   // * It is put onto the bus for two cycles
   // * Read data is then registered
   // * It then has several phases to make it back to the bus register
 
   // Number of cycles we preload counter with, depending on access
`define WRITE_CYCLES 5'h04
`define READ_CYCLES  5'h0c
 
   // We let the commands settle for 2 cycles (0, 1) and then sample
   // *but* data could have come on either cycle 0 _or_ 3, so check both
`define REQ_CHECK_CYCLE ((clk_200_phase == 3'd3)||(clk_200_phase == 3'd7))
 
   // Write OE - whole time, doesn't matter so much
`define WRITE_OE_CYCLE  (|clk_200_cycle_counter)
   // Read OE, just the first  two cycles
//`define READ_OE_CYCLE  (clk_200_cycle_counter > (`READ_CYCLES - 5'h4))
`define READ_OE_CYCLE  (|clk_200_cycle_counter)
 
   // Sample data from RAM 2 cycles after we sample the addr from system bus
`define RAM_DATA_SAMPLE_CYCLE (!(|we_r) && clk_200_cycle_counter == (`READ_CYCLES - 5'h5))
 
   // Cycle when we pull sram_we_l low   
`define WRITE_CE_CYCLE (reg_from_bus_domain & (|we))
   // Cycle when we ouptut the CE
`define READ_CE_CYCLE (reg_from_bus_domain & !(|we))
 
   // Register stuff when we've just loaded the counter
`define REG_FROM_BUS_DOMAIN reg_from_bus_domain
 
   // CE 2 cycles dring writes, only one during reads
   always @(posedge clk_200)
     sram_ce_l <= 0;
     //sram_ce_l <= ~((`WRITE_CE_CYCLE) || (`READ_CE_CYCLE ));
 
 
   always @(posedge clk_200)
     sram_adv_ld_l <= 0;
     //sram_adv_ld_l <= ~((`WRITE_CE_CYCLE) || (`READ_CE_CYCLE ));
 
   always @(posedge clk_200)
     sram_we_l <= ~(`WRITE_CE_CYCLE);
 
   always @(posedge clk_200)
     if (`REG_FROM_BUS_DOMAIN)
       sram_addr[21:1] <= wb_adr_i[22:2];
 
   always @(posedge clk_200)
     if (`REG_FROM_BUS_DOMAIN)
       sram_dq_o <= wb_dat_i;
 
   always @(posedge clk_200)
     if (`REG_FROM_BUS_DOMAIN)
       sram_bw_l <= ~we;
 
   always @(posedge clk_200)
     sram_oe_l <= ~((`READ_OE_CYCLE) & !(|(we_r | we)));
 
   always @(posedge clk_200)
     ssram_controller_oe_l = ~((`WRITE_OE_CYCLE) & (|we_r));
 
   // Register data from SSRAM
   always @(posedge clk_200)
     if (`RAM_DATA_SAMPLE_CYCLE)
       data_rd[31:0] <= sram_dq_i[31:0];
 
   assign wb_dat_o = data_rd;
 
   // Determine if we've got a request
   // This logic means the bus' control signals are slightly
   // more constrained than the data and address.
   always @(posedge clk_200)
     begin
	if (|clk_200_cycle_counter)
	  clk_200_cycle_counter <= clk_200_cycle_counter - 1;
	else if (`REQ_CHECK_CYCLE)
	  if (wb_cyc_i & wb_stb_i)
	       clk_200_cycle_counter <= wb_we_i ? 
					       `WRITE_CYCLES : `READ_CYCLES;
	  else
	       clk_200_cycle_counter <= 0;
     end // always @ (posedge clk_200)
 
   always @(posedge clk_200)
     begin
	reg_from_bus_domain <= ((`REQ_CHECK_CYCLE) & wb_cyc_i & wb_stb_i & !(|clk_200_cycle_counter));
	reg_from_bus_domain_r <= reg_from_bus_domain;
     end   
 
   // Must clear 
   always @(posedge clk_200)
     if (`REG_FROM_BUS_DOMAIN)
       we_r <= we;
     else if (!(|clk_200_cycle_counter))
       we_r <= 0;   
 
 
   /* SSRAM Clocking configuration */
 
   /* DCM de-skewing SSRAM clock via external trace */
   DCM_BASE dcm0
     (/*AUTOINST*/
      // Outputs
      .CLK0                              (dcm0_clk0_prebufg),
      .CLK180                            (),
      .CLK270                            (),
      .CLK2X180                          (),
      .CLK2X                             (),
      .CLK90                             (),
      .CLKDV                             (),
      .CLKFX180                          (),
      .CLKFX                             (),
      .LOCKED                            (dcm0_locked),
      // Inputs
      .CLKFB                             (sram_clk_fb),
      .CLKIN                             (clk_200),
      .RST                               (wb_rst));
 
   BUFG dcm0_clk0_bufg
     (// Outputs
      .O                                 (dcm0_clk0),
      // Inputs
      .I                                 (dcm0_clk0_prebufg));
 
   /* Generate the DQ bus tristate buffers */
   genvar i;
   generate
      for (i=0; i<32; i=i+1) begin: SSRAM_DQ_TRISTATE
	 IOBUF U (.O(sram_dq_i[i]),
		  .IO(sram_dq_io[i]),
		  .I(sram_dq_o[i]),
		  .T(ssram_controller_oe_l));
      end
   endgenerate
 
endmodule // xilinx_ssram
 
// Local Variables:
// verilog-library-directories:(".")
// verilog-library-extensions:(".v" ".h")
// End:
 

Go to most recent revision | Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.