////////////////////////////////////////////////////////////////////// // Author: lsilvest // // Create Date: 02/03/2008 // // Module Name: memory_wb_to_mig // // Target Devices: Spartan 3E starter kit Rev D // // Tool versions: Tested with ISE WebPack 9.2 // // Description: This module converts the Xilinx MIG2.0 DDR SDRAM // proprietary interface to a wishbone interface // usable with the Opencores Ethernet core. // // //////////////////////////////////////////////////////////////////////////////// // Copyright (c) 2008 Authors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. ///////////////////////////////////////////////////////////////////////////////// module memory_wb_to_mig ( // wishbone interface: input wb_clk_i, input wb_rst_i, input [31:0] wb_adr_i, input [31:0] wb_dat_i, input [3:0] wb_sel_i, input wb_we_i, input wb_cyc_i, input wb_stb_i, output reg wb_ack_o, output reg wb_err_o, output reg [31:0] wb_dat_o, // MIG 2.0 interface: input mig_clk90, input mig_init_done, input [31:0] mig_output_data, output [31:0] mig_input_data, output [25:0] mig_input_address, output reg [2:0] mig_command, input mig_cmd_ack, input mig_data_valid, output reg mig_burst_done, input mig_ar_done, input mig_auto_ref_req, input mig_wait_200us, output [3:0] mig_data_mask ); reg [2:0] current_init_state; reg [2:0] next_init_state; reg [2:0] current_state; reg [2:0] next_state; reg [23:0] cntr; // user commands: localparam NOP_CMD = 3'b000, PRECHARGE_CMD = 3'b001, INIT_CMD = 3'b010, WRITE_CMD = 3'b100, READ_CMD = 3'b110; localparam INIT_INIT = 3'b000, WAIT_200us = 3'b001, SEND_INIT = 3'b010, WAIT_INIT = 3'b011, INIT_DONE = 3'b100; parameter IDLE_ST = 3'b000, READ_START_ST = 3'b001, WRITE_START_ST = 3'b010, WAIT_ACK_ST = 3'b011, COMMAND_ACKED_ST = 3'b100, BURST_DONE_ST = 3'b101, WAIT_ACK_N_ST = 3'b110, ACK_N_ST = 3'b111; localparam WAIT_BURST_DONE_VALUE = 24'b11; reg wb_ack_o_sync; assign mig_input_address = {wb_adr_i[20:9],wb_adr_i[8], 1'b0, wb_adr_i[7:0], wb_adr_i[22:21]}; assign mig_data_mask = ~wb_sel_i; // see ethernet module assign mig_input_data = wb_dat_i; initial begin wb_ack_o <= 0; wb_ack_o_sync <= 0; wb_err_o <= 0; cntr <= 0; mig_command <= NOP_CMD; current_init_state <= 0; next_init_state <= 0; current_state <= 0; next_state <= 0; end // process the command always @ (negedge mig_clk90) begin if (current_init_state == SEND_INIT) begin mig_command <= INIT_CMD; end else if (current_state == READ_START_ST) begin mig_command <= READ_CMD; end else if (current_state == WRITE_START_ST) begin mig_command <= WRITE_CMD; end else if (current_init_state == WAIT_INIT || current_state == BURST_DONE_ST) begin mig_command <= NOP_CMD; end end // general counter always @ (negedge mig_clk90) begin if (current_state == WAIT_ACK_ST) begin cntr <= WAIT_BURST_DONE_VALUE; end else begin cntr <= cntr - 1; end end // set burst_done output to memory always @ (negedge mig_clk90) begin // should be set 3 clocks after a READ or WRITE command has been issued: if (current_state == BURST_DONE_ST) mig_burst_done <= 1'b1; else mig_burst_done <= 1'b0; end // memory output data to the wishbone interface: always @ (negedge mig_clk90) begin if (mig_data_valid) begin case (wb_adr_i[1:0]) 2'b00: // word access wb_dat_o <= mig_output_data; 2'b10: // half access wb_dat_o <= {16'b0,mig_output_data[15:0]}; 2'b01: // byte access wb_dat_o <= {8'b0,mig_output_data[23:16],16'b0}; 2'b11: wb_dat_o <= {14'b0,mig_output_data[7:0]}; endcase end end // state processing always@ (negedge mig_clk90) begin if (wb_rst_i) begin current_init_state <= INIT_INIT; end else begin current_init_state <= next_init_state; end end always@ (negedge mig_clk90) begin if (wb_rst_i) begin current_state <= IDLE_ST; end else begin current_state <= next_state; end end // synchronizing to the wishbone clock always @ (negedge mig_clk90) begin if (((current_state == WAIT_ACK_N_ST) && !mig_cmd_ack) || current_state == ACK_N_ST) begin wb_ack_o_sync <= 1'b1; end else begin wb_ack_o_sync <= 1'b0; end end // this is the ack output to the wb interface clocked by the wishbone // clock always @ (posedge wb_clk_i) begin if (wb_ack_o_sync) begin wb_ack_o <= 1'b1; end else begin wb_ack_o <= 1'b0; end end // memory initialization: always @ (*) begin if (wb_rst_i) begin next_init_state = INIT_INIT; end else begin case (current_init_state) INIT_INIT: if (!mig_wait_200us) next_init_state = SEND_INIT; else next_init_state = INIT_INIT; SEND_INIT: next_init_state = WAIT_INIT; WAIT_INIT: if (mig_init_done) next_init_state = INIT_DONE; else next_init_state = WAIT_INIT; INIT_DONE: next_init_state = INIT_DONE; default next_init_state = INIT_DONE; endcase // case (current_init_state) end // else: !if(wb_rst_i) end // always @ (*) // state machine after memory initialization always @ (*) begin if (wb_rst_i) begin next_state = IDLE_ST; end else if (mig_init_done) begin case (current_state) IDLE_ST: if (wb_cyc_i & wb_stb_i) begin if (!wb_we_i) begin next_state = READ_START_ST; end else begin next_state = WRITE_START_ST; end end else begin next_state = IDLE_ST; end READ_START_ST: next_state = WAIT_ACK_ST; WRITE_START_ST: next_state = WAIT_ACK_ST; WAIT_ACK_ST: if (mig_cmd_ack) next_state = COMMAND_ACKED_ST; else next_state = WAIT_ACK_ST; COMMAND_ACKED_ST: if (!cntr) begin next_state = BURST_DONE_ST; end else begin next_state = COMMAND_ACKED_ST; end BURST_DONE_ST: next_state = WAIT_ACK_N_ST; WAIT_ACK_N_ST: if (!mig_cmd_ack) begin next_state = ACK_N_ST; end else next_state = WAIT_ACK_N_ST; ACK_N_ST: next_state = IDLE_ST; default: next_state = IDLE_ST; endcase // case (current_state) end else begin// if (mig_init_done) next_state = IDLE_ST; end // else: !if(init_done) end endmodule