//sata_link_layer_read.v
|
//sata_link_layer_read.v
|
/*
|
/*
|
Distributed under the MIT license.
|
Distributed under the MIT license.
|
Copyright (c) 2011 Dave McCoy (dave.mccoy@cospandesign.com)
|
Copyright (c) 2011 Dave McCoy (dave.mccoy@cospandesign.com)
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
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
|
this software and associated documentation files (the "Software"), to deal in
|
the Software without restriction, including without limitation the rights to
|
the Software without restriction, including without limitation the rights to
|
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
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
|
of the Software, and to permit persons to whom the Software is furnished to do
|
so, subject to the following conditions:
|
so, subject to the following conditions:
|
|
|
The above copyright notice and this permission notice shall be included in all
|
The above copyright notice and this permission notice shall be included in all
|
copies or substantial portions of the Software.
|
copies or substantial portions of the Software.
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
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
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
SOFTWARE.
|
SOFTWARE.
|
*/
|
*/
|
|
|
|
|
`include "sata_defines.v"
|
`include "sata_defines.v"
|
|
|
module sata_link_layer_read (
|
module sata_link_layer_read (
|
|
|
input rst, //reset
|
input rst, //reset
|
input clk,
|
input clk,
|
|
|
input phy_ready,
|
input phy_ready,
|
input en,
|
input en,
|
output idle,
|
output idle,
|
|
|
input sync_escape,
|
input sync_escape,
|
input dbg_hold,
|
input dbg_hold,
|
|
|
input detect_align,
|
input detect_align,
|
input detect_sync,
|
input detect_sync,
|
input detect_x_rdy,
|
input detect_x_rdy,
|
input detect_sof,
|
input detect_sof,
|
input detect_eof,
|
input detect_eof,
|
input detect_wtrm,
|
input detect_wtrm,
|
input detect_holda,
|
input detect_holda,
|
input detect_hold,
|
input detect_hold,
|
input detect_cont,
|
input detect_cont,
|
input detect_xrdy_xrdy,
|
input detect_xrdy_xrdy,
|
|
|
output [31:0] tx_dout,
|
output [31:0] tx_dout,
|
output tx_isk,
|
output tx_is_k,
|
|
|
input [31:0] rx_din,
|
input [31:0] rx_din,
|
input [3:0] rx_isk,
|
input [3:0] rx_is_k,
|
|
|
output reg read_strobe,
|
output reg read_strobe,
|
output reg [31:0] read_data,
|
output reg [31:0] read_data,
|
input read_ready,
|
input read_ready,
|
output read_start,
|
output read_start,
|
output read_finished,
|
output read_finished,
|
output reg remote_abort,
|
output reg remote_abort,
|
|
|
output reg crc_ok,
|
output reg crc_ok,
|
// output wire crc_ok,
|
// output wire crc_ok,
|
|
|
input data_scrambler_en,
|
input data_scrambler_en,
|
input is_device,
|
input is_device,
|
output [3:0] lax_r_state
|
output [3:0] lax_r_state
|
|
|
|
|
|
|
);
|
);
|
//Primatives
|
//Primatives
|
parameter IDLE = 4'h0;
|
parameter IDLE = 4'h0;
|
parameter READ_START = 4'h1;
|
parameter READ_START = 4'h1;
|
parameter READ = 4'h2;
|
parameter READ = 4'h2;
|
parameter READ_END = 4'h3;
|
parameter READ_END = 4'h3;
|
parameter SEND_STATUS = 4'h4;
|
parameter SEND_STATUS = 4'h4;
|
|
|
//Registers/Wires
|
//Registers/Wires
|
reg [3:0] state;
|
reg [3:0] state;
|
|
|
reg send_r_rdy;
|
reg send_r_rdy;
|
reg send_r_ip;
|
reg send_r_ip;
|
reg send_r_err;
|
reg send_r_err;
|
reg send_r_ok;
|
reg send_r_ok;
|
reg send_hold;
|
reg send_hold;
|
reg send_holda;
|
reg send_holda;
|
reg send_sync;
|
reg send_sync;
|
|
|
//CRC
|
//CRC
|
//XXX: Tie the CRC_EN to an incomming data dword
|
//XXX: Tie the CRC_EN to an incomming data dword
|
wire crc_en;
|
|
wire [31:0] crc_din;
|
wire [31:0] crc_din;
|
wire [31:0] crc_dout;
|
|
reg crc_data;
|
|
reg crc_check;
|
|
|
|
reg [31:0] prev_crc;
|
reg [31:0] prev_crc;
|
reg [31:0] prev_data;
|
reg [31:0] prev_data;
|
wire data_valid;
|
wire data_valid;
|
reg first_dword;
|
reg first_dword;
|
|
|
|
|
|
|
//Descrambler
|
//Descrambler
|
wire descr_en;
|
wire descr_en;
|
wire [31:0] descr_din;
|
wire [31:0] descr_din;
|
wire [31:0] descr_dout;
|
wire [31:0] descr_dout;
|
|
|
//SubModules
|
//SubModules
|
crc c (
|
|
.rst (rst || idle ),
|
|
.clk (clk ),
|
|
.en (crc_en ),
|
|
.din (crc_din ),
|
|
.dout (crc_dout )
|
|
);
|
|
|
|
scrambler descr (
|
scrambler descr (
|
.rst (rst || idle),
|
.rst (rst || idle),
|
.clk (clk ),
|
.clk (clk ),
|
.prim_scrambler (0 ),
|
.prim_scrambler (1'b0 ),
|
.en (descr_en ),
|
.en (descr_en ),
|
.din (rx_din ),
|
.din (rx_din ),
|
.dout (descr_dout )
|
.dout (descr_dout )
|
);
|
);
|
|
|
|
|
|
|
//Asynchronous Logic
|
//Asynchronous Logic
|
assign idle = (state == IDLE);
|
assign idle = (state == IDLE);
|
assign tx_dout = (send_r_rdy) ? `PRIM_R_RDY :
|
assign tx_dout = (send_r_rdy) ? `PRIM_R_RDY :
|
(send_r_ip) ? `PRIM_R_IP :
|
(send_r_ip) ? `PRIM_R_IP :
|
(send_r_err) ? `PRIM_R_ERR :
|
(send_r_err) ? `PRIM_R_ERR :
|
(send_r_ok) ? `PRIM_R_OK :
|
(send_r_ok) ? `PRIM_R_OK :
|
(send_hold) ? `PRIM_HOLD :
|
(send_hold) ? `PRIM_HOLD :
|
(send_sync) ? `PRIM_SYNC :
|
(send_sync) ? `PRIM_SYNC :
|
(send_holda) ? `PRIM_HOLDA :
|
(send_holda) ? `PRIM_HOLDA :
|
`PRIM_SYNC;
|
`PRIM_SYNC;
|
|
|
assign tx_isk = ( send_r_rdy ||
|
assign tx_is_k = ( send_r_rdy ||
|
send_r_ip ||
|
send_r_ip ||
|
send_r_err ||
|
send_r_err ||
|
send_r_ok ||
|
send_r_ok ||
|
send_hold ||
|
send_hold ||
|
send_holda ||
|
send_holda ||
|
send_sync);
|
send_sync);
|
|
|
assign crc_din = (data_scrambler_en) ? descr_dout : rx_din;
|
assign crc_din = (data_scrambler_en) ? descr_dout : rx_din;
|
//assign read_data = (read_strobe) ? rx_din : 32'h0;
|
//assign read_data = (read_strobe) ? rx_din : 32'h0;
|
assign read_finished = detect_eof;
|
assign read_finished = detect_eof;
|
assign read_start = detect_sof;
|
assign read_start = detect_sof;
|
assign data_valid = (state == READ) &&
|
assign data_valid = (state == READ) &&
|
(rx_isk == 0) &&
|
(rx_is_k == 0) &&
|
(!detect_hold) &&
|
(!detect_hold) &&
|
(!detect_holda) &&
|
(!detect_holda) &&
|
(!detect_align);
|
(!detect_align);
|
|
|
assign crc_en = data_valid;
|
|
assign descr_en = (data_scrambler_en && (detect_sof || data_valid));
|
assign descr_en = (data_scrambler_en && (detect_sof || data_valid));
|
assign descr_din = (data_valid) ? rx_din : 32'h00000000;
|
assign descr_din = (data_valid) ? rx_din : 32'h00000000;
|
//assign crc_ok = (prev_data == prev_crc);
|
//assign crc_ok = (prev_data == prev_crc);
|
|
|
assign lax_r_state = state;
|
assign lax_r_state = state;
|
|
|
//Synchronous Logic
|
//Synchronous Logic
|
always @ (posedge clk) begin
|
always @ (posedge clk) begin
|
if (rst) begin
|
if (rst) begin
|
state <= IDLE;
|
state <= IDLE;
|
send_r_rdy <= 0;
|
send_r_rdy <= 0;
|
send_r_ip <= 0;
|
send_r_ip <= 0;
|
send_r_err <= 0;
|
send_r_err <= 0;
|
send_r_ok <= 0;
|
send_r_ok <= 0;
|
send_hold <= 0;
|
send_hold <= 0;
|
send_holda <= 0;
|
send_holda <= 0;
|
send_sync <= 0;
|
send_sync <= 0;
|
|
|
crc_ok <= 0;
|
crc_ok <= 0;
|
|
|
prev_crc <= 0;
|
prev_crc <= 0;
|
prev_data <= 0;
|
prev_data <= 0;
|
read_data <= 0;
|
read_data <= 0;
|
read_strobe <= 0;
|
read_strobe <= 0;
|
first_dword <= 0;
|
first_dword <= 0;
|
|
|
remote_abort <= 0;
|
remote_abort <= 0;
|
|
|
end
|
end
|
else begin
|
else begin
|
read_strobe <= 0;
|
read_strobe <= 0;
|
remote_abort <= 0;
|
remote_abort <= 0;
|
|
|
if (phy_ready) begin
|
if (phy_ready) begin
|
send_r_rdy <= 0;
|
send_r_rdy <= 0;
|
send_r_ip <= 0;
|
send_r_ip <= 0;
|
send_r_err <= 0;
|
send_r_err <= 0;
|
send_r_ok <= 0;
|
send_r_ok <= 0;
|
send_hold <= 0;
|
send_hold <= 0;
|
send_sync <= 0;
|
send_sync <= 0;
|
send_holda <= 0;
|
send_holda <= 0;
|
end
|
end
|
|
|
case (state)
|
case (state)
|
IDLE: begin
|
IDLE: begin
|
read_data <= 0;
|
read_data <= 0;
|
send_sync <= 1;
|
send_sync <= 1;
|
if (!detect_align) begin
|
if (!detect_align) begin
|
crc_ok <= 0;
|
crc_ok <= 0;
|
prev_crc <= 0;
|
prev_crc <= 0;
|
prev_data <= 0;
|
prev_data <= 0;
|
if (detect_x_rdy) begin
|
if (detect_x_rdy) begin
|
if (detect_xrdy_xrdy) begin
|
if (detect_xrdy_xrdy) begin
|
if (!is_device) begin
|
if (!is_device) begin
|
if (read_ready || sync_escape) begin
|
if (read_ready || sync_escape) begin
|
//Transport is ready
|
//Transport is ready
|
if (phy_ready) begin
|
if (phy_ready) begin
|
send_r_rdy <= 1;
|
send_r_rdy <= 1;
|
state <= READ_START;
|
state <= READ_START;
|
end
|
end
|
end
|
end
|
end
|
end
|
end
|
end
|
else begin
|
else begin
|
if (read_ready || sync_escape) begin
|
if (read_ready || sync_escape) begin
|
//Transport is ready
|
//Transport is ready
|
//XXX: I think this is okay because remote will continue to send X_RDY Primative
|
//XXX: I think this is okay because remote will continue to send X_RDY Primative
|
if (phy_ready) begin
|
if (phy_ready) begin
|
send_r_rdy <= 1;
|
send_r_rdy <= 1;
|
state <= READ_START;
|
state <= READ_START;
|
end
|
end
|
end
|
end
|
end
|
end
|
// else begin
|
// else begin
|
// //Transport Read is not ready
|
// //Transport Read is not ready
|
// send_sync <= 1;
|
// send_sync <= 1;
|
// end
|
// end
|
end
|
end
|
end
|
end
|
end
|
end
|
READ_START: begin
|
READ_START: begin
|
//wait for a start of frame
|
//wait for a start of frame
|
send_r_rdy <= 1;
|
send_r_rdy <= 1;
|
if (detect_sync) begin
|
if (detect_sync) begin
|
remote_abort <= 1;
|
remote_abort <= 1;
|
state <= IDLE;
|
state <= IDLE;
|
end
|
end
|
else if (detect_sof) begin
|
else if (detect_sof) begin
|
state <= READ;
|
state <= READ;
|
send_r_ip <= 1;
|
send_r_ip <= 1;
|
first_dword <= 1;
|
first_dword <= 1;
|
end
|
end
|
end
|
end
|
READ: begin
|
READ: begin
|
if (sync_escape) begin
|
if (sync_escape) begin
|
send_sync <= 1;
|
send_sync <= 1;
|
if (detect_sync) begin
|
if (detect_sync) begin
|
state <= IDLE;
|
state <= IDLE;
|
end
|
end
|
end
|
end
|
else begin
|
else begin
|
if (detect_eof) begin
|
if (detect_eof) begin
|
//check the CRC
|
//check the CRC
|
state <= READ_END;
|
state <= READ_END;
|
send_r_ip <= 1;
|
send_r_ip <= 1;
|
//if (prev_data == prev_crc) begin
|
//if (prev_data == prev_crc) begin
|
if (prev_data == prev_crc) begin
|
if (prev_data == prev_crc) begin
|
crc_ok <= 1;
|
crc_ok <= 1;
|
end
|
end
|
end
|
end
|
else begin
|
else begin
|
if (detect_sync) begin
|
if (detect_sync) begin
|
remote_abort <= 1;
|
remote_abort <= 1;
|
state <= IDLE;
|
state <= IDLE;
|
end
|
end
|
else if (!read_ready || dbg_hold) begin
|
else if (!read_ready || dbg_hold) begin
|
//we should still have 20 DWORD of data to write
|
//we should still have 20 DWORD of data to write
|
send_hold <= 1;
|
send_hold <= 1;
|
end
|
end
|
else if (detect_hold) begin
|
else if (detect_hold) begin
|
send_holda <= 1;
|
send_holda <= 1;
|
end
|
end
|
else begin
|
else begin
|
send_r_ip <= 1;
|
send_r_ip <= 1;
|
end
|
end
|
end
|
end
|
if (data_valid) begin
|
if (data_valid) begin
|
if (first_dword) begin
|
if (first_dword) begin
|
first_dword <= 0;
|
first_dword <= 0;
|
end
|
end
|
else begin
|
else begin
|
read_strobe <= 1;
|
read_strobe <= 1;
|
end
|
end
|
read_data <= prev_data;
|
read_data <= prev_data;
|
if (data_scrambler_en) begin
|
if (data_scrambler_en) begin
|
prev_data <= descr_dout;
|
prev_data <= descr_dout;
|
end
|
end
|
else begin
|
else begin
|
prev_data <= rx_din;
|
prev_data <= rx_din;
|
end
|
end
|
prev_crc <= crc_din;
|
prev_crc <= crc_din;
|
end
|
end
|
|
|
end
|
end
|
|
|
//put data into the incomming buffer
|
//put data into the incomming buffer
|
//check to see if we have enough room for 20 more dwords
|
//check to see if we have enough room for 20 more dwords
|
//if not send a hold
|
//if not send a hold
|
end
|
end
|
READ_END: begin
|
READ_END: begin
|
//send r ok or r err
|
//send r ok or r err
|
//XXX: Watch out for PHY_READY
|
//XXX: Watch out for PHY_READY
|
//if CRC checks out OK then send an R_OK
|
//if CRC checks out OK then send an R_OK
|
//if CRC does not check out then send an R_ERR
|
//if CRC does not check out then send an R_ERR
|
//if (phy_ready) begin
|
//if (phy_ready) begin
|
if (crc_ok) begin
|
if (crc_ok) begin
|
send_r_ok <= 1;
|
send_r_ok <= 1;
|
state <= SEND_STATUS;
|
state <= SEND_STATUS;
|
end
|
end
|
else begin
|
else begin
|
send_r_err <= 1;
|
send_r_err <= 1;
|
state <= SEND_STATUS;
|
state <= SEND_STATUS;
|
end
|
end
|
//end
|
//end
|
end
|
end
|
SEND_STATUS: begin
|
SEND_STATUS: begin
|
if (send_r_ok) begin
|
if (send_r_ok) begin
|
send_r_ok <= 1;
|
send_r_ok <= 1;
|
end
|
end
|
else begin
|
else begin
|
send_r_err <= 1;
|
send_r_err <= 1;
|
end
|
end
|
if (detect_sync) begin
|
if (detect_sync) begin
|
state <= IDLE;
|
state <= IDLE;
|
end
|
end
|
end
|
end
|
default: begin
|
default: begin
|
state <= IDLE;
|
state <= IDLE;
|
end
|
end
|
endcase
|
endcase
|
end
|
end
|
end
|
end
|
endmodule
|
endmodule
|
|
|