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

Subversion Repositories nysa_sata

[/] [nysa_sata/] [trunk/] [rtl/] [phy/] [oob_controller.v] - Rev 4

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

//oob_controller.v
/*
Distributed under the MIT license.
Copyright (c) 2011 Dave McCoy (dave.mccoy@cospandesign.com)
 
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.
*/
 
 
`include "sata_defines.v"
 
module oob_controller (
 
input               rst,              //reset
input               clk,
 
input               platform_ready,   //the underlying physical platform is
output  reg         platform_error,   //Underlyaing physal platform received an error, this should probably be a reset
output  reg         linkup,           //link is finished
 
output  reg         tx_comm_reset,     //send a init OOB signal
output  reg         tx_comm_wake,     //send a wake OOB signal
input               tx_oob_complete,  //Phy has said we are finished with this OOB transaction
 
input               comm_init_detect, //detected an init
input               comm_wake_detect, //detected a wake on the rx lines
 
input       [31:0]  rx_din,
input       [3:0]   rx_is_k,
input               rx_is_elec_idle,
input               rx_byte_is_aligned,
input               phy_error,
 
output  reg [31:0]  tx_dout,
output  reg         tx_is_k,
output  reg         tx_set_elec_idle,
output      [3:0]   lax_state
 
 
);
 
//platform signals
 
//Parameters
 
//States
parameter           IDLE                    = 4'h0;
parameter           SEND_RESET              = 4'h1;
parameter           WAIT_FOR_INIT           = 4'h2;
parameter           WAIT_FOR_NO_INIT        = 4'h3;
parameter           WAIT_FOR_CONFIGURE_END  = 4'h4;
parameter           SEND_WAKE               = 4'h5;
parameter           WAIT_FOR_WAKE           = 4'h6;
parameter           WAIT_FOR_NO_WAKE        = 4'h7;
parameter           WAIT_FOR_IDLE           = 4'h8;
parameter           WAIT_FOR_ALIGN          = 4'h9;
parameter           SEND_ALIGN              = 4'hA;
parameter           DETECT_SYNC             = 4'hB;
parameter           READY                   = 4'hC;
 
//Registers/Wires
reg         [3:0]   state;
reg         [31:0]  timer;
reg         [1:0]   no_align_count;
reg         [3:0]   retries;
 
//timer used to send 'INITs', WAKEs' and read them
wire                timeout;
wire                align_detected;
wire                sync_detected;
 
//Submodules
//Asynchronous Logic
assign              timeout         = (timer == 0);
//assign              align_detected  = ((rx_is_k > 0) && (rx_din == `PRIM_ALIGN) && !phy_error);
//assign              align_detected  = ((rx_is_k > 0) && (rx_din == `PRIM_ALIGN));
assign              align_detected  = ((rx_is_k > 0) && (rx_din == `PRIM_ALIGN) && rx_byte_is_aligned);
assign              sync_detected   = ((rx_is_k > 0) && (rx_din == `PRIM_SYNC));
assign              lax_state       = state;
 
//Synchronous Logic
initial begin
  tx_set_elec_idle      <=  1;
end
 
always @ (posedge clk) begin
  if (rst) begin
    state               <=  IDLE;
    linkup              <=  0;
    timer               <=  0;
    tx_comm_reset       <=  0;
    tx_comm_wake        <=  0;
    tx_dout             <=  0;
    tx_is_k             <=  0;
    tx_set_elec_idle    <=  1;
    no_align_count      <=  0;
    platform_error      <=  0;
    retries             <=  0;
  end
  else begin
    //to support strobes, continuously reset the following signals
    tx_comm_reset       <=  0;
    tx_comm_wake        <=  0;
 
    tx_is_k             <=  0;
 
 
    //timer (when reache 0 timeout has occured)
    if (timer > 0) begin
      timer                 <=  timer - 1;
    end
 
    //main state machine, if this reaches ready an initialization sequence has completed
    case (state)
      IDLE: begin
        platform_error      <=  0;
        linkup              <=  0;
        tx_set_elec_idle    <=  1;
        if (platform_ready) begin
          $display ("oob_controller: send RESET");
          //the platform is ready
          //  PLL has locked onto a clock
          //  DCM has generated the correct clocks
          timer             <=  32'h000000A2;
          state             <=  SEND_RESET;
          tx_comm_reset     <=  1;
        end
      end
      SEND_RESET: begin
//XXX: In the groundhog COMM RESET was continuously issued for a long period of time
        //send the INIT sequence, this will initiate a communication with the
        //SATA hard drive, or reset it so that it can be initiated to state
 
        //strobe the comm init so that the platform will send an INIT OOB signal
        if (timeout || tx_oob_complete) begin
          timer               <=  `INITIALIZE_TIMEOUT;
          state               <=  WAIT_FOR_INIT;
          $display ("oob_controller: wait for INIT");
        end
      end
      WAIT_FOR_INIT: begin
        //wait for a response from the SATA harddrive, if the timeout occurs
        //go back to the SEND_RESET state
        if (comm_init_detect) begin
          //HD said 'sup' go to a wake
          //timer             <=  0;
          timer             <=  32'h00001000;
          state             <=  WAIT_FOR_NO_INIT;
          $display ("oob_controller: wait for INIT to go low");
        end
        if (timeout) begin
          $display ("oob_controller: timed out while waiting for INIT");
          state             <=  IDLE;
        end
      end
      WAIT_FOR_NO_INIT: begin
        //wait for the init signal to go low from the device
        if (!comm_init_detect && (timeout || tx_oob_complete)) begin
          $display ("oob_controller: INIT deasserted");
          $display ("oob_controller: start configuration");
          state             <=  WAIT_FOR_CONFIGURE_END;
        end
      end
      WAIT_FOR_CONFIGURE_END: begin
          $display ("oob_controller: System is configured");
          state             <=  SEND_WAKE;
          timer             <=  32'h0000009B;
          tx_comm_wake      <=  1;
        //end
      end
      SEND_WAKE:  begin
//XXX: In the groundhog COMM WAKE was continuously send for a long period of time
        //Send the WAKE sequence to the hard drive to initiate a wakeup sequence
//XXX: Is this timeout correct?
        //880uS
        if (timeout || tx_oob_complete) begin
          //timer               <=  32'd`INITIALIZE_TIMEOUT;
          timer               <=  32'h000203AD;
          state               <=  WAIT_FOR_WAKE;
        end
      end
      WAIT_FOR_WAKE:  begin
        //Wait for the device to send a COMM Wake
        if (comm_wake_detect) begin
          //Found a comm wake, now wait for the device to stop sending WAKE
          timer             <=  0;
          state             <=  WAIT_FOR_NO_WAKE;
          $display ("oob_controller: WAKE detected");
        end
        if (timeout) begin
          //Timeout occured before reading WAKE
          state             <=  IDLE;
          $display ("oob_controller: timed out while waiting for WAKE to be asserted");
        end
      end
      WAIT_FOR_NO_WAKE: begin
        if (!comm_wake_detect) begin
          //The device stopped sending comm wake
//XXX: Is this timeout correct?
          //880uS
          $display ("oob_controller: detected WAKE deasserted");
          $display ("oob_controller: Send Dialtone, wait for ALIGN");
//Going to add more timeout
          //timer           <=  32'h0203AD;
          timer           <=  32'h0203AD;
          state           <=  WAIT_FOR_ALIGN;
          //state           <=  WAIT_FOR_IDLE;
          retries         <=  4;
        end
      end
      /*
      WAIT_FOR_IDLE: begin
        if (!rx_is_elec_idle) begin
          state           <=  WAIT_FOR_ALIGN;
          timer           <=  32'h0101D0;
        end
        else if (timeout) begin
          if (retries > 0) begin
            timer         <=  32'h0203AD;
            retries       <=  retries - 1;
          end
          if (retries == 0) begin
            state         <= IDLE;
          end
        end
      end
      */
      WAIT_FOR_ALIGN: begin
        //transmit the 'dialtone' continuously
        //since we need to start sending actual data (not OOB signals, get out
        //  of tx idle)
        tx_set_elec_idle    <=  0;
        //a sequence of 0's and 1's
        tx_dout             <=  `DIALTONE;
        tx_is_k             <=  0;
        //$display ("rx din: %h, k: %h", rx_din, rx_is_k);
        if (align_detected) begin
          //we got something from the device!
          timer             <=  0;
          //now send an align from my side
          state             <=  SEND_ALIGN;
          no_align_count    <=  0;
          $display ("oob_controller: ALIGN detected");
          $display ("oob_controller: Send out my ALIGNs");
        end
        if (timeout) begin
          //didn't read an align in time :( reset
          $display ("oob_controller: timed out while waiting for AIGN");
          state             <=  IDLE;
        end
      end
      SEND_ALIGN: begin
        tx_dout             <=  `PRIM_ALIGN;
        tx_is_k             <=  1;
        if (!align_detected) begin
          $display ("oob_controller: detected ALIGN deasserted");
//XXX: Groundhog detects the SYNC primitve before declaring linkup
          if (no_align_count == 3) begin
            $display ("oob_controller: ready");
            state           <=  READY;
          end
          else begin
            no_align_count  <=  no_align_count + 2'b01;
          end
        end
      end
      DETECT_SYNC: begin
        if (sync_detected) begin
          state             <=  READY;
        end
      end
      READY:  begin
        linkup              <=  1;
        /*
        if (phy_error) begin
          platform_error    <=  1;
        end
        */
        if (comm_init_detect) begin
          state             <=  IDLE;
        end
      end
      default: begin
        state               <=  IDLE;
      end
    endcase
 
  end
end
 
endmodule
 
 

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.