transport.v 52.5 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
/*******************************************************************************
 * Module: transport
 * Date: 2015-07-11  
 * Author: Alexey     
 * Description: sata transport layer implementation
 *
 * Copyright (c) 2015 Elphel, Inc.
 * transport.v is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * transport.v file 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/> .
20 21 22 23 24 25 26 27 28 29 30 31 32
 *
 * Additional permission under GNU GPL version 3 section 7:
 * If you modify this Program, or any covered work, by linking or combining it
 * with independent modules provided by the FPGA vendor only (this permission
 * does not extend to any 3-rd party modules, "soft cores" or macros) under
 * different license terms solely for the purpose of generating binary "bitstream"
 * files and/or simulating the code, the copyright holders of this Program give
 * you the right to distribute the covered work without those independent modules
 * as long as the source code for them is available from the FPGA vendor free of
 * charge, and there is no dependence on any encrypted modules for simulating of
 * the combined code. This permission applies to you if the distributed code
 * contains all the components and scripts required to completely simulate it
 * with at least one of the Free Software programs.
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
 *******************************************************************************/
module transport #(
    parameter DATA_BYTE_WIDTH = 4
)
(
    input   wire    clk,
    input   wire    rst,

    // link layer (LL) control

    // issue a frame
    output  wire    frame_req,
    // frame started to be transmitted
    input   wire    frame_ack,
    // frame issue was rejected because of incoming frame with higher priority
    input   wire    frame_rej,
    // LL is not ready to receive a frame request. frame_req shall be low if busy is asserted
    input   wire    frame_busy,
    // frame was transmitted w/o probles and successfully received @ a device side
    input   wire    frame_done_good,
    // frame was transmitted, but device messages of problems with receiving
    input   wire    frame_done_bad,

    // LL reports of an incoming frame transmission. They're always allowed and have the highest priority
    input   wire    incom_start,
    // LL reports of a completion of an incoming frame transmission.
    input   wire    incom_done,
60 61
    // LL reports of errors in current FIS
    input   wire    incom_invalidate, // TODO
62 63 64 65 66 67
    // TL analyzes FIS and returnes if FIS makes sense.
    output  wire    incom_ack_good,
    // ... and if it doesn't
    output  wire    incom_ack_bad,

    // transmission interrupts
68
    // TL demands to brutally cancel current transaction TODO
Alexey Grebenkin's avatar
Alexey Grebenkin committed
69
    output  wire    sync_escape_req,
70
    // acknowlegement of a successful reception TODO
Alexey Grebenkin's avatar
Alexey Grebenkin committed
71
    input   wire    sync_escape_ack,
72
    // TL demands to stop current recieving session TODO
Alexey Grebenkin's avatar
Alexey Grebenkin committed
73
    output  wire    incom_stop_req,
74 75 76 77 78 79 80 81 82 83 84 85 86 87

    // controls from a command layer (CL)
    // FIS type, ordered by CL
    input   wire    [2:0]   cmd_type,
    // request itself
    input   wire            cmd_val,
    // destination port
    input   wire    [3:0]   cmd_port,
    // if cmd got into processing, busy asserts, when TL is ready to receive a new cmd, busy deasserts
    output  wire            cmd_busy,
    // indicates completion of a request
    output  wire            cmd_done_good,
    // request is completed, but device wasn't able to receive
    output  wire            cmd_done_bad,
88

89 90 91 92 93 94 95 96 97 98 99 100 101 102
    // shadow registers TODO reduce outputs/inputs count. or not
    // actual registers are stored in CL
    input   wire    [31:0]  sh_data_in,
    input   wire    [15:0]  sh_feature_in,
    input   wire    [47:0]  sh_lba_in,
    input   wire    [15:0]  sh_count_in,
    input   wire    [7:0]   sh_command_in,
    input   wire    [7:0]   sh_dev_in,
    input   wire    [7:0]   sh_control_in,
    input   wire            sh_autoact_in,
    input   wire            sh_inter_in,
    input   wire            sh_dir_in,
    input   wire    [63:0]  sh_dma_id_in,
    input   wire    [31:0]  sh_buf_off_in,
Alexey Grebenkin's avatar
Alexey Grebenkin committed
103
    input   wire    [31:0]  sh_dma_cnt_in,
104
    input   wire            sh_notif_in,
Alexey Grebenkin's avatar
Alexey Grebenkin committed
105
    input   wire    [15:0]  sh_tran_cnt_in,
106
    input   wire    [3:0]   sh_port_in,
107 108
    // TL decodes register writes and sends corresponding issues to CL
    output  wire    [47:0]  sh_lba_out,
109 110
    output  wire    [15:0]  sh_count_out,
    output  wire    [7:0]   sh_command_out,
111 112
    output  wire    [7:0]   sh_err_out,
    output  wire    [7:0]   sh_status_out,
113
    output  wire    [7:0]   sh_estatus_out, // E_Status
114
    output  wire    [7:0]   sh_dev_out,
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
    output  wire    [3:0]   sh_port_out,
    output  wire            sh_inter_out,
    output  wire            sh_dir_out,
    output  wire    [63:0]  sh_dma_id_out,
    output  wire    [31:0]  sh_dma_off_out,
    output  wire    [31:0]  sh_dma_cnt_out,
    output  wire    [15:0]  sh_tran_cnt_out, // Transfer Count
    output  wire            sh_notif_out,
    output  wire            sh_autoact_out,
    output  wire            sh_lba_val_out,
    output  wire            sh_count_val_out,
    output  wire            sh_command_val_out,
    output  wire            sh_err_val_out,
    output  wire            sh_status_val_out,
    output  wire            sh_estatus_val_out, // E_Status
    output  wire            sh_dev_val_out,
    output  wire            sh_port_val_out,
    output  wire            sh_inter_val_out,
    output  wire            sh_dir_val_out,
    output  wire            sh_dma_id_val_out,
    output  wire            sh_dma_off_val_out,
    output  wire            sh_dma_cnt_val_out,
    output  wire            sh_tran_cnt_val_out, // Transfer Count
    output  wire            sh_notif_val_out,
    output  wire            sh_autoact_val_out,

141 142 143 144 145 146 147 148 149 150 151 152

    // shows if dma activate was received (a pulse)
    output  wire            got_dma_activate,
    output  wire    [3:0]   got_dma_activate_port,
    // if CL made a mistake in controlling data FIS length
    output  wire            data_limit_exceeded,

    // LL data
    // data inputs from LL
    input   wire    [DATA_BYTE_WIDTH*8 - 1:0]   ll_data_in,
    input   wire    [DATA_BYTE_WIDTH/2 - 1:0]   ll_data_mask_in,
    input   wire                                ll_data_val_in,
153
    input   wire                                ll_data_last_in,
154 155 156 157 158 159
    // transport layer tells if its inner buffer is almost full
    output  wire                                ll_data_busy_out,

    // data outputs to LL
    output  wire    [DATA_BYTE_WIDTH*8 - 1:0]   ll_data_out,
    // not implemented yet TODO
Alexey Grebenkin's avatar
Alexey Grebenkin committed
160
    output  wire    [DATA_BYTE_WIDTH/2 - 1:0]   ll_data_mask_out,
161 162 163 164 165 166 167 168 169 170 171
    output  wire                                ll_data_last_out,
    output  wire                                ll_data_val_out,
    input   wire                                ll_data_strobe_in,

    // CL data
    // required content is bypassed from ll, other is trimmed
    // only content of data FIS, starting from 1st dword. Max burst = 2048 dwords
    // data outputs to CL
    output  wire    [DATA_BYTE_WIDTH*8 - 1:0]   cl_data_out,
    output  wire    [DATA_BYTE_WIDTH/2 - 1:0]   cl_data_mask_out,
    output  wire                                cl_data_val_out,
172
    output  wire                                cl_data_last_out,
173 174 175 176
    // transport layer tells if its inner buffer is almost full
    input   wire                                cl_data_busy_in,

    // data inputs from CL
177
    input   wire    [DATA_BYTE_WIDTH*8 - 1:0]   cl_data_in,
178
    // not implemented yet TODO
179
    input   wire    [DATA_BYTE_WIDTH/2 - 1:0]   cl_data_mask_in,
180 181 182 183 184 185 186 187
    input   wire                                cl_data_last_in,
    input   wire                                cl_data_val_in,
    output  wire                                cl_data_strobe_out,


    // watchdog timers calls. They shall be handled in TL, but for debug purposes are wired to the upper level
    // when eof acknowledgement is not received after sent FIS
    output  wire    watchdog_eof,
188 189
    // when too many dwords is in current FIS
    output  wire    watchdog_dwords
190 191
);

192 193
reg [7:0]   state;

Alexey Grebenkin's avatar
Alexey Grebenkin committed
194 195 196 197 198
//TODO
assign sync_escape_req = 1'b0;
assign incom_stop_req = 1'b0;
assign cl_data_strobe_out = 1'b0;

199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222
// How much time does device have to response on EOF
parameter [13:0]  WATCHDOG_EOF_LIMIT = 14'd1000;

// must have a local reserve copy of shadow registers in case of 
// a) received FIS with incorrect length (seems like an error, so no registers shall be written)
// b) incoming transmission overrides outcoming, so we have to latch outcoming values in real shadow registers
//    while storing incoming ones in the local copy
reg [47:0]  loc_lba;
reg [15:0]  loc_count;
reg [7:0]   loc_command;
reg [7:0]   loc_err;
reg [7:0]   loc_status;
reg [7:0]   loc_estatus; // E_Status
reg [7:0]   loc_dev;
reg [3:0]   loc_port;
reg         loc_inter;
reg         loc_dir;
reg [63:0]  loc_dma_id;
reg [31:0]  loc_dma_off;
reg [31:0]  loc_dma_cnt;
reg [15:0]  loc_tran_cnt; // Transfer Count
reg         loc_notif;
reg         loc_autoact;

223

224 225 226 227 228 229 230 231 232
// latching cmd inputs
reg [3:0]   cmd_port_r;
reg [2:0]   cmd_type_r;
always @ (posedge clk)
    cmd_type_r  <= rst ? 3'h0 : cmd_val ? cmd_type : cmd_type_r;
always @ (posedge clk)
    cmd_port_r  <= rst ? 4'h0 : cmd_val ? cmd_port : cmd_port_r;

// incomming command type decode, shows which type of FIS shall be issued
233 234 235 236 237
localparam [2:0] CMD_TYPE_REG_DEV     = 3'h0; // Reg H2D, bit C -> 0
localparam [2:0] CMD_TYPE_REG_CMD     = 3'h1; // Reg H2D, bit C -> 1
localparam [2:0] CMD_TYPE_DMA_SETUP   = 3'h2;
localparam [2:0] CMD_TYPE_DATA        = 3'h3;
localparam [2:0] CMD_TYPE_BIST_ACT    = 3'h4;
238 239 240 241 242 243 244 245

// current header dword
wire    [31:0]  ll_header_dword;
// current dword shall be header's
wire            ll_header_val;
// if last data dword is header's
wire            ll_header_last;
// incorrect size or unmatched type of a received FIS
246 247 248 249 250
reg             bad_fis_received; 
// if a FIS has wrong size, make sure it would stop, universal dword counter
reg     [13:0]  dword_cnt;
// FIS dword size exceeded condition
assign  watchdog_dwords = dword_cnt == 14'd2049;
251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303
// ask for a receiving termination in case of errors
reg             incom_stop_req_timeout;

// global TL fsm
/*
    idle -----> outcoming FIS ----> outcoming ----non-data--> fill dwords -------------------------+
      |             |if rej                     |                                                  |
      |             |                           +-----data--> make header --> bypass data from CL -+
      |             V                                                                              |
      +-------> incoming FIS -------detect type---non-data--> parse dwords, write sh regs ---------+ 
                                        |                                                          |
                                        +-------------data--> get header ---> bypass data to CL -----> done
*/

localparam  STATE_IDLE           = 8'h0;
localparam  STATE_INCOMING       = 8'h1;
localparam  STATE_OUTCOMING      = 8'h2;
localparam  STATE_IN_DATA        = 8'h10; // Data FIS from device
localparam  STATE_IN_REG_1       = 8'h20; // Register FIS Device to Host: 1st dword
localparam  STATE_IN_REG_2       = 8'h21; // Register FIS Device to Host: 2nd dword
localparam  STATE_IN_REG_3       = 8'h22; // Register FIS Device to Host: 3rd dword
localparam  STATE_IN_REG_4       = 8'h23; // Register FIS Device to Host: 4th dword
localparam  STATE_IN_REG_ERR     = 8'h24; // Register FIS Device to Host: Error happened
localparam  STATE_IN_DMAA_ERR    = 8'h30; // DMA Activate: Error Happened
localparam  STATE_IN_DMAS_1      = 8'h40; // DMA Setup FIS device to host: 1st dword
localparam  STATE_IN_DMAS_2      = 8'h41; // DMA Setup FIS device to host: 2nd dword
localparam  STATE_IN_DMAS_3      = 8'h42; // DMA Setup FIS device to host: 3rd dword
localparam  STATE_IN_DMAS_4      = 8'h43; // DMA Setup FIS device to host: 4th dword
localparam  STATE_IN_DMAS_5      = 8'h44; // DMA Setup FIS device to host: 5th dword
localparam  STATE_IN_DMAS_6      = 8'h45; // DMA Setup FIS device to host: 6th dword
localparam  STATE_IN_DMAS_ERR    = 8'h46; // DMA Setup FIS device to host: Error happened
localparam  STATE_IN_BIST_1      = 8'h50; // BIST Activate FIS Device to Host: 1st dword
localparam  STATE_IN_BIST_2      = 8'h51; // BIST Activate FIS Device to Host: 2nd dword
localparam  STATE_IN_BIST_ERR    = 8'h52; // BIST Activate FIS Device to Host: Error happened
localparam  STATE_IN_PIOS_1      = 8'h60; // PIO Setup FIS: 1st dword
localparam  STATE_IN_PIOS_2      = 8'h61; // PIO Setup FIS: 2nd dword
localparam  STATE_IN_PIOS_3      = 8'h62; // PIO Setup FIS: 3rd dword
localparam  STATE_IN_PIOS_4      = 8'h63; // PIO Setup FIS: 4th dword
localparam  STATE_IN_PIOS_ERR    = 8'h64; // PIO Setup FIS: Error happened
localparam  STATE_IN_SDB_1       = 8'h70; // Set Device Bits FIS: 1st dword
localparam  STATE_IN_SDB_ERR     = 8'h70; // Set Device Bits FIS: Error happened
localparam  STATE_OUT_DATA_H     = 8'h80; // Data FIS from host: header
localparam  STATE_OUT_DATA_D     = 8'h81; // Data FIS from host: payload
localparam  STATE_OUT_REG        = 8'h90; // Register FIS Host to Device
localparam  STATE_OUT_DMAS       = 8'ha0; // DMA Setup FIS Host to Device
localparam  STATE_OUT_BIST       = 8'hb0; // BIST Activate FIS Host to Device
localparam  STATE_OUT_WAIT_RESP  = 8'hc0; // 
localparam  STATE_IN_UNRECOG     = 8'hf0; // Unrecognized FIS from Device

always @ (posedge clk)
    if (rst)
    begin
        state                   <= STATE_IDLE;
304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322
        dword_cnt               <= 14'h0;
        incom_stop_req_timeout  <= 1'b0;
        bad_fis_received        <= 1'b0;
        loc_lba                 <= 48'h0;
        loc_count               <= 32'h0;
        loc_command             <= 8'h0;
        loc_err                 <= 8'h0;
        loc_status              <= 8'h0;
        loc_estatus             <= 8'h0;
        loc_dev                 <= 8'h0;
        loc_port                <= 4'h0;
        loc_inter               <= 1'h0;
        loc_dir                 <= 1'h0;
        loc_dma_id              <= 64'h0;
        loc_dma_off             <= 32'h0;
        loc_dma_cnt             <= 32'h0;
        loc_tran_cnt            <= 16'h0;
        loc_notif               <= 1'h0;
        loc_autoact             <= 1'h0;
323 324 325 326 327
    end
    else
        case (state)
            STATE_IDLE:
            begin
328 329 330
                dword_cnt               <= 14'h0;
                incom_stop_req_timeout  <= 1'b0;
                bad_fis_received        <= 1'b0;
331 332 333 334 335 336 337
                if (frame_req)
                    state   <= STATE_OUTCOMING;
                else
                if (incom_start | frame_req)
                    state   <= STATE_INCOMING;
                else
                    state   <= STATE_IDLE;
338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354

                loc_lba      <= sh_lba_in;
                loc_count    <= sh_count_in;
                loc_command  <= sh_command_in;
                loc_err      <= 8'h0;
                loc_status   <= 8'h0;
                loc_estatus  <= 8'h0;
                loc_dev      <= 8'h0;
                loc_port     <= sh_port_in;
                loc_inter    <= sh_inter_in;
                loc_dir      <= sh_dir_in;
                loc_dma_id   <= sh_dma_id_in;
                loc_dma_off  <= sh_buf_off_in;
                loc_dma_cnt  <= sh_dma_cnt_in;
                loc_tran_cnt <= sh_tran_cnt_in;
                loc_notif    <= sh_notif_in;
                loc_autoact  <= sh_autoact_in;
355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372
            end

            STATE_INCOMING:
            // enter state when we're starting to get a FIS, leave after 1st dword is received
            begin
                if (ll_data_val_in)
                // if 0-th dword came
                    case (ll_data_in[7:0])
                    // act depending on packet type

                        8'h34:
                        // register 
                        begin
                            if (~ll_data_last_in)
                            begin
                                loc_port    <= ll_data_in[11:8];
                                loc_inter   <= ll_data_in[14];
                                loc_status  <= ll_data_in[23:16];
373
                                loc_err     <= ll_data_in[31:24];
374 375 376 377 378 379 380 381 382 383 384 385 386 387
                                state       <= STATE_IN_REG_1;
                            end
                            else
                            // an error state, too little dwords transfered
                            begin
                                bad_fis_received    <= 1'b1;
                                state               <= STATE_IDLE;
                            end
                        end

                        8'h39:
                        // DMA Activate
                        begin
                            if (~ll_data_last_in)
388
                            begin
389
                                state       <= STATE_IN_DMAA_ERR;
390 391
                                dword_cnt   <= 14'h1;
                            end
392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450
                            else
                            begin
                                // got_dma_activate - wire assigment
                                state       <= STATE_IDLE;
                            end
                        end

                        8'h41:
                        // DMA Setup
                        begin
                            if (~ll_data_last_in)
                            begin
                                loc_port    <= ll_data_in[11:8];
                                loc_dir     <= ll_data_in[13];
                                loc_inter   <= ll_data_in[14];
                                loc_autoact <= ll_data_in[15];
                                state       <= STATE_IN_DMAS_1;
                            end
                            else
                            // an error state, too little dwords transfered
                            begin
                                bad_fis_received    <= 1'b1;
                                state               <= STATE_IDLE;
                            end
                        end

                        8'h46:
                        // Data FIS
                        begin
                            if (~ll_data_last_in)
                            begin
                                loc_port    <= ll_data_in[11:8];
                                dword_cnt   <= 14'h1;
                                state       <= STATE_IN_DATA;
                            end
                            else
                            // an error state, too little dwords transfered
                            begin
                                bad_fis_received    <= 1'b1;
                                state               <= STATE_IDLE;
                            end
                        end

                        8'h58:
                        // BIST
                        begin
                            // for now skips payload, just controls length TODO
                            state   <= STATE_IN_BIST_1;
                        end

                        8'h5f:
                        // PIO setup
                        begin
                            if (~ll_data_last_in)
                            begin
                                loc_port        <= ll_data_in[11:8];
                                loc_dir         <= ll_data_in[13];
                                loc_inter       <= ll_data_in[14];
                                loc_status      <= ll_data_in[23:16];
451
                                loc_err         <= ll_data_in[31:24];
452 453 454 455 456 457 458 459 460 461 462 463 464 465
                                state           <= STATE_IN_PIOS_1;
                            end
                            else
                            // an error state, too little dwords transfered
                            begin
                                bad_fis_received    <= 1'b1;
                                state               <= STATE_IDLE;
                            end
                        end

                        8'ha1:
                        // Set Device Bits
                        begin
                            if (~ll_data_last_in)
466
                            begin
467 468 469 470
                                loc_inter       <= ll_data_in[14];
                                loc_notif       <= ll_data_in[15];
                                loc_status[2:0] <= ll_data_in[19:17];
                                loc_status[6:4] <= ll_data_in[23:21];
471
                                loc_err         <= ll_data_in[31:24];
472
                                state           <= STATE_IN_SDB_1;
473
                            end
474 475 476 477 478 479 480 481 482 483 484
                            else
                            // an error state, too little dwords transfered
                            begin
                                bad_fis_received    <= 1'b1;
                                state               <= STATE_IDLE;
                            end
                        end

                        default:
                        // no known FIS type matched
                        begin
485 486
                            dword_cnt   <= 14'h0;
                            state       <= STATE_IN_UNRECOG;
487 488 489 490 491 492 493 494 495
                        end
                    endcase
            end

            STATE_OUTCOMING:
            // enter state when we're issuing a FIS, leave when got an ack from ll (FIS started to transmit)
            // or if FIS won't start because of incoming transmission. In such case outcoming request parameter shall be latched TODO or not?
            begin
                dword_cnt   <= 14'h0;
496 497 498 499 500 501
                state       <= frame_rej ? STATE_INCOMING :
                               frame_ack & cmd_type_r == CMD_TYPE_REG_DEV   ? STATE_OUT_REG    :
                               frame_ack & cmd_type_r == CMD_TYPE_REG_CMD   ? STATE_OUT_REG    :
                               frame_ack & cmd_type_r == CMD_TYPE_DMA_SETUP ? STATE_OUT_DMAS   :
                               frame_ack & cmd_type_r == CMD_TYPE_DATA      ? STATE_OUT_DATA_H :
                               frame_ack & cmd_type_r == CMD_TYPE_BIST_ACT  ? STATE_OUT_BIST   :
502 503 504 505 506 507 508
                                                                              STATE_OUTCOMING;
            end

            STATE_IN_DATA:
            // receiving data from Data FIS, bypass it into buffer at upper level
            begin
                if (incom_done)
509
                // EOF received, CRC good
510 511 512 513 514 515 516
                begin
                    state   <= STATE_IDLE;
                end
                else 
                if (ll_data_val_in)
                begin
                    if (dword_cnt == 14'd2049)
517
                    // if too much data for a data FIS TODO handle this exception properly
518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544
                        state       <= STATE_IDLE; 
                    else
                    // continuing receiving data
                    begin
                        dword_cnt   <= dword_cnt + 1'b1;
                        state       <= STATE_IN_DATA;
                    end
                end
            end

            STATE_IN_REG_1:
            // receiving register FIS, dword by dword
            begin
                if (ll_data_val_in)
                    if (ll_data_last_in)
                    // incorrect frame size
                    begin
                        bad_fis_received <= 1'b1;
                        state            <= STATE_IDLE;
                    end
                    else
                    // going to the next dword, parse current one: {Device, LBA High, LBA Mid, LBA Low}
                    begin
                        loc_lba[7:0]    <= ll_data_in[7:0];
                        loc_lba[23:16]  <= ll_data_in[15:8];
                        loc_lba[39:32]  <= ll_data_in[23:16];
                        loc_dev[7:0]    <= ll_data_in[31:24];
545
                        state           <= STATE_IN_REG_2;
546 547 548 549 550 551 552 553 554 555 556
                    end
            end

            STATE_IN_REG_2:
            // receiving register FIS, dword by dword
            begin
                if (ll_data_val_in)
                    if (ll_data_last_in)
                    // incorrect frame size
                    begin
                        bad_fis_received <= 1'b1;
557
                        state            <= STATE_IDLE;
558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576
                    end
                    else
                    // going to the next dword, parse current one: {Reserved, LBA High (exp), LBA Mid (exp), LBA Low (exp)}
                    begin
                        loc_lba[15:8]   <= ll_data_in[7:0];
                        loc_lba[31:24]  <= ll_data_in[15:8];
                        loc_lba[47:40]  <= ll_data_in[23:16];
                        state           <= STATE_IN_REG_3;
                    end
            end

            STATE_IN_REG_3:
            // receiving register FIS, dword by dword
            begin
                if (ll_data_val_in)
                    if (ll_data_last_in)
                    // incorrect frame size
                    begin
                        bad_fis_received <= 1'b1;
577
                        state            <= STATE_IDLE;
578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593
                    end
                    else
                    // going to the next dword, parse current one: {Reserved, Reserved, Sector Count (exp), Sector Count}
                    begin
                        loc_count[15:0] <= ll_data_in[15:0];
                        state           <= STATE_IN_REG_4;
                    end
            end

            STATE_IN_REG_4:
            // receiving register FIS, dword by dword
            begin
                if (ll_data_val_in)
                    if (ll_data_last_in)
                    // correct frame size, finishing
                    begin
594
                        state            <= STATE_IDLE;
595 596 597 598 599
                    end
                    else
                    // incorrect frame size
                    begin
                        state           <= STATE_IN_REG_ERR;
600
                        dword_cnt       <= 14'h4;
601 602 603 604 605 606 607 608 609 610 611 612 613 614 615
                    end
            end

            STATE_IN_REG_ERR:
            // FIS was started as REG, but for some reason it has a size more than needed
            // just wait until it's over and assert an error
            begin
                if (ll_data_val_in)
                    if (ll_data_last_in)
                    begin
                        bad_fis_received <= 1'b1;
                        state            <= STATE_IDLE;
                    end
                    else
                    begin
616
                        if (watchdog_dwords)
617 618 619 620 621 622
                        // if for some reason FIS continue transferring for too long, terminate it
                        begin
                            state                   <= STATE_IDLE;
                            incom_stop_req_timeout  <= 1'b1;
                        end
                        else
623
                            dword_cnt <= dword_cnt + 1'b1;
624 625 626 627 628 629 630 631 632 633 634 635 636 637 638
                    end
            end

            STATE_IN_DMAA_ERR:
            // FIS was started as DMA Activate, but for some reason it has a size more than needed
            // just wait until it's over and assert an error
            begin
                if (ll_data_val_in)
                    if (ll_data_last_in)
                    begin
                        bad_fis_received <= 1'b1;
                        state            <= STATE_IDLE;
                    end
                    else
                    begin
639
                        if (watchdog_dwords)
640 641 642 643 644 645
                        // if for some reason FIS continue transferring for too long, terminate it
                        begin
                            state                   <= STATE_IDLE;
                            incom_stop_req_timeout  <= 1'b1;
                        end
                        else
646
                            dword_cnt <= dword_cnt + 1'b1;
647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680
                    end
            end

            STATE_IN_DMAS_1:
            // receiving DMA Setup FIS, dword by dword
            begin
                if (ll_data_val_in)
                    if (ll_data_last_in)
                    // incorrect frame size
                    begin
                        bad_fis_received <= 1'b1;
                        state            <= STATE_IDLE;
                    end
                    else
                    // going to the next dword, parse current one: DMA Buffer Id Low
                    begin
                        loc_dma_id[31:0]    <= ll_data_in[31:0];
                        state               <= STATE_IN_DMAS_2;
                    end
            end

            STATE_IN_DMAS_2:
            // receiving DMA Setup FIS, dword by dword
            begin
                if (ll_data_val_in)
                    if (ll_data_last_in)
                    // incorrect frame size
                    begin
                        bad_fis_received <= 1'b1;
                        state            <= STATE_IDLE;
                    end
                    else
                    // going to the next dword, parse current one: DMA Buffer Id High
                    begin
681 682
                        loc_dma_id[63:32]   <= ll_data_in[31:0];
                        state               <= STATE_IN_DMAS_3;
683 684 685 686 687 688 689 690 691 692 693
                    end
            end

            STATE_IN_DMAS_3:
            // receiving DMA Setup FIS, dword by dword
            begin
                if (ll_data_val_in)
                    if (ll_data_last_in)
                    // incorrect frame size
                    begin
                        bad_fis_received <= 1'b1;
694
                        state            <= STATE_IDLE;
695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710
                    end
                    else
                    // going to the next dword, parse current one: Reserved
                    begin
                        state           <= STATE_IN_DMAS_4;
                    end
            end

            STATE_IN_DMAS_4:
            // receiving DMA Setup FIS, dword by dword
            begin
                if (ll_data_val_in)
                    if (ll_data_last_in)
                    // incorrect frame size
                    begin
                        bad_fis_received <= 1'b1;
711
                        state            <= STATE_IDLE;
712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728
                    end
                    else
                    // going to the next dword, parse current one: DMA Buffer Offset
                    begin
                        loc_dma_off[31:0]   <= ll_data_in[31:0];
                        state               <= STATE_IN_DMAS_5;
                    end
            end

            STATE_IN_DMAS_5:
            // receiving DMA Setup FIS, dword by dword
            begin
                if (ll_data_val_in)
                    if (ll_data_last_in)
                    // incorrect frame size
                    begin
                        bad_fis_received <= 1'b1;
729
                        state            <= STATE_IDLE;
730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745
                    end
                    else
                    // going to the next dword, parse current one: DMA Transfer Count
                    begin
                        loc_dma_cnt[31:0]   <= ll_data_in[31:0];
                        state               <= STATE_IN_DMAS_6;
                    end
            end

            STATE_IN_DMAS_6:
            // receiving DMA Setup FIS, dword by dword
            begin
                if (ll_data_val_in)
                    if (ll_data_last_in)
                    // correct frame size, finishing, current dword: Reserved
                    begin
746
                        state            <= STATE_IDLE;
747 748 749 750 751
                    end
                    else
                    // incorrect frame size
                    begin
                        state           <= STATE_IN_DMAS_ERR;
752
                        dword_cnt       <= 14'h6;
753 754 755 756 757 758 759 760 761 762 763 764 765 766 767
                    end
            end

            STATE_IN_DMAS_ERR:
            // FIS was started as DMA Setup, but for some reason it has a size more than needed
            // just wait until it's over and assert an error
            begin
                if (ll_data_val_in)
                    if (ll_data_last_in)
                    begin
                        bad_fis_received <= 1'b1;
                        state            <= STATE_IDLE;
                    end
                    else
                    begin
768
                        if (watchdog_dwords)
769 770 771 772 773 774
                        // if for some reason FIS continue transferring for too long, terminate it
                        begin
                            state                   <= STATE_IDLE;
                            incom_stop_req_timeout  <= 1'b1;
                        end
                        else
775
                            dword_cnt <= dword_cnt + 1'b1;
776 777 778 779 780 781 782 783 784 785 786
                    end
            end

            STATE_IN_BIST_1:
            // receiving BIST FIS, dword by dword
            begin
                if (ll_data_val_in)
                    if (ll_data_last_in)
                    // incorrect frame size
                    begin
                        bad_fis_received <= 1'b1;
787
                        state            <= STATE_IDLE;
788 789 790 791 792 793 794 795 796 797 798 799 800 801 802
                    end
                    else
                    // going to the next dword, parse current one: TODO
                    begin
                        state               <= STATE_IN_BIST_2;
                    end
            end

            STATE_IN_BIST_2:
            // receiving BIST FIS, dword by dword
            begin
                if (ll_data_val_in)
                    if (ll_data_last_in)
                    // correct frame size, finishing, current dword: Reserved
                    begin
803
                        state            <= STATE_IDLE;
804 805 806 807 808
                    end
                    else
                    // incorrect frame size
                    begin
                        state           <= STATE_IN_BIST_ERR;
809
                        dword_cnt       <= 14'h2;
810 811 812 813 814 815 816 817 818 819 820 821 822 823 824
                    end
            end

            STATE_IN_BIST_ERR:
            // FIS was started as BIST Activate, but for some reason it has a size more than needed
            // just wait until it's over and assert an error
            begin
                if (ll_data_val_in)
                    if (ll_data_last_in)
                    begin
                        bad_fis_received <= 1'b1;
                        state            <= STATE_IDLE;
                    end
                    else
                    begin
825
                        if (watchdog_dwords)
826 827 828 829 830 831
                        // if for some reason FIS continue transferring for too long, terminate it
                        begin
                            state                   <= STATE_IDLE;
                            incom_stop_req_timeout  <= 1'b1;
                        end
                        else
832
                            dword_cnt <= dword_cnt + 1'b1;
833 834 835 836 837 838 839 840 841 842 843
                    end
            end

            STATE_IN_PIOS_1:
            // receiving PIO Setup FIS, dword by dword
            begin
                if (ll_data_val_in)
                    if (ll_data_last_in)
                    // incorrect frame size
                    begin
                        bad_fis_received <= 1'b1;
844
                        state            <= STATE_IDLE;
845 846 847 848 849 850 851
                    end
                    else
                    // going to the next dword, parse current one: {Device, LBA High, LBA Mid, LBA Low}
                    begin
                        loc_lba[7:0]    <= ll_data_in[7:0];  
                        loc_lba[23:16]  <= ll_data_in[15:8];
                        loc_lba[39:32]  <= ll_data_in[23:16];
852
                        loc_dev         <= ll_data_in[31:24];
853 854 855 856 857 858 859 860
                        state           <= STATE_IN_PIOS_2;
                    end
            end

            STATE_IN_PIOS_2:
            // receiving PIO Setup FIS, dword by dword
            begin
                if (ll_data_val_in)
861 862 863 864 865 866 867 868 869 870 871 872 873 874
                    if (ll_data_last_in)
                    // incorrect frame size
                    begin
                        bad_fis_received <= 1'b1;
                        state            <= STATE_IDLE;
                    end
                    else
                    // going to the next dword, parse current one: {Reserved, LBA High (exp), LBA Mid (exp), LBA Low (exp)}
                    begin
                        loc_lba[15:8]   <= ll_data_in[7:0];
                        loc_lba[31:24]  <= ll_data_in[15:8];
                        loc_lba[47:40]  <= ll_data_in[23:16];
                        state           <= STATE_IN_PIOS_3;
                    end
875 876 877 878 879 880 881 882 883 884
            end

            STATE_IN_PIOS_3:
            // receiving PIOS FIS, dword by dword
            begin
                if (ll_data_val_in)
                    if (ll_data_last_in)
                    // incorrect frame size
                    begin
                        bad_fis_received <= 1'b1;
885
                        state            <= STATE_IDLE;
886 887 888 889 890 891 892 893 894 895
                    end
                    else
                    // going to the next dword, parse current one: {E_Status, Reserved, Sector Count (exp), Sector Count}
                    begin
                        loc_count[15:0] <= ll_data_in[15:0];
                        loc_estatus     <= ll_data_in[31:24];
                        state           <= STATE_IN_PIOS_4;
                    end
            end

896 897
            STATE_IN_PIOS_4:
            // receiving PIO Setup FIS, dword by dword
898 899 900 901 902 903
            begin
                if (ll_data_val_in)
                    if (ll_data_last_in)
                    // correct frame size, finishing, current dword: {Reserved, Transfer Count}
                    begin
                        loc_tran_cnt    <= ll_data_in[15:0];
904
                        state           <= STATE_IDLE;
905 906 907 908 909
                    end
                    else
                    // incorrect frame size
                    begin
                        state           <= STATE_IN_BIST_ERR;
910
                        dword_cnt       <= 14'h4;
911 912 913 914 915 916 917 918 919 920 921 922 923 924 925
                    end
            end

            STATE_IN_PIOS_ERR:
            // FIS was started as PIO Setup Activate, but for some reason it has a size more than needed
            // just wait until it's over and assert an error
            begin
                if (ll_data_val_in)
                    if (ll_data_last_in)
                    begin
                        bad_fis_received <= 1'b1;
                        state            <= STATE_IDLE;
                    end
                    else
                    begin
926
                        if (watchdog_dwords)
927 928 929 930 931 932
                        // if for some reason FIS continue transferring for too long, terminate it
                        begin
                            state                   <= STATE_IDLE;
                            incom_stop_req_timeout  <= 1'b1;
                        end
                        else
933
                            dword_cnt <= dword_cnt + 1'b1;
934 935 936 937 938 939 940 941 942 943
                    end
            end

            STATE_IN_SDB_1:
            // receiving Set Device Bits FIS, dword by dword
            begin
                if (ll_data_val_in)
                    if (ll_data_last_in)
                    // correct frame size, finishing, current dword: Reserved
                    begin
944
                        state           <= STATE_IDLE;
945 946 947 948 949
                    end
                    else
                    // incorrect frame size
                    begin
                        state           <= STATE_IN_SDB_ERR;
950
                        dword_cnt       <= 14'h1;
951 952 953 954 955 956 957 958 959 960 961 962 963 964 965
                    end
            end

            STATE_IN_SDB_ERR:
            // FIS was started as Set Device Bits FIS, but for some reason it has a size more than needed
            // just wait until it's over and assert an error
            begin
                if (ll_data_val_in)
                     if (ll_data_last_in)
                     begin
                         bad_fis_received <= 1'b1;
                         state            <= STATE_IDLE;
                     end
                     else
                     begin
966
                         if (watchdog_dwords)
967 968 969 970 971 972
                         // if for some reason FIS continue transferring for too long, terminate it
                         begin
                             state                   <= STATE_IDLE;
                             incom_stop_req_timeout  <= 1'b1;
                         end
                         else
973
                             dword_cnt <= dword_cnt + 1'b1;
974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992
                     end
            end

            STATE_OUT_DATA_H:
            // Send data FIS header
            begin
                if (ll_data_strobe_in)
                begin
                    state       <= STATE_OUT_DATA_D;
                    dword_cnt   <= 14'h1;
                end
            end

            STATE_OUT_DATA_D:
            // Send data FIS data payload
            begin
                if (ll_data_strobe_in)
                begin
                    if (cl_data_last_in)
993
                    begin
994 995 996
                    // All data is transmitted
                        dword_cnt   <= 14'h0;
                        state       <= STATE_OUT_WAIT_RESP;
997
                    end
998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015
                    else
                    if (dword_cnt == 2048)
                    // data_limit_exceed - wire assigned
                        state       <= STATE_IDLE;
                    else
                    begin
                        state       <= STATE_OUT_DATA_D;
                        dword_cnt   <= dword_cnt + 1'b1;
                    end
                end
            end

            STATE_OUT_REG:
            // Register Host 2 Device FIS
            begin
                if (ll_data_strobe_in)
                    // 5 header dwords, then wait for a reception on a device side
                    if (dword_cnt[2:0] == 3'h4)
1016
                    begin
1017 1018
                        dword_cnt   <= 14'h0;
                        state       <= STATE_OUT_WAIT_RESP;
1019
                    end
1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032
                    else
                    begin
                        state       <= STATE_OUT_REG;
                        dword_cnt   <= dword_cnt + 1'b1;
                    end
            end

            STATE_OUT_DMAS:
            // DMA Setup outcoming FIS
            begin
                if (ll_data_strobe_in)
                    // 7 header dwords, then wait for a reception on a device side
                    if (dword_cnt[2:0] == 3'h6)
1033
                    begin
1034 1035
                        dword_cnt   <= 14'h0;
                        state       <= STATE_OUT_WAIT_RESP;
1036
                    end
1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048
                    else
                    begin
                        state       <= STATE_OUT_DMAS;
                        dword_cnt   <= dword_cnt + 1'b1;
                    end
            end

            STATE_OUT_BIST:
            begin
                if (ll_data_strobe_in)
                    // 3 header dwords, then wait for a reception on a device side
                    if (dword_cnt[2:0] == 3'h2)
1049
                    begin
1050 1051
                        dword_cnt   <= 14'h0;
                        state       <= STATE_OUT_WAIT_RESP;
1052
                    end
1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076
                    else
                    begin
                        state       <= STATE_OUT_BIST;
                        dword_cnt   <= dword_cnt + 1'b1;
                    end
            end

            STATE_OUT_WAIT_RESP:
            begin
                if (frame_done_good)
                    // cmd_done_good wire assigned
                    state       <= STATE_IDLE;
                else 
                if (frame_done_bad)
                    // cmd_done_bad wire assigned
                    state       <= STATE_IDLE;
                else
                if (dword_cnt == WATCHDOG_EOF_LIMIT)
                // in here dword_cnt works as a watchdog timer
                begin
                    state       <= STATE_IDLE; 
                    // watchdog_eof wire assigned
                    // for now while debugging let it be indicated on higher level TODO Choose exception. May be send incom stop req. 
                    //      Be aware of no response for that. In such case go for rst for ll. Or better make link_reset -> 1. And dont forget for oob
1077
                end
1078 1079 1080 1081 1082 1083 1084 1085 1086
                else
                begin
                    dword_cnt   <= dword_cnt + 1'b1;
                    state       <= STATE_OUT_WAIT_RESP;
                end
            end

            STATE_IN_UNRECOG:
            begin
1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102
                if (incom_done | incom_invalidate)
                // transmission complete
                // incom_ack_bad wire assigned
                    state   <= STATE_IDLE;
                else
                if (watchdog_dwords)
                begin
                    state                   <= STATE_IDLE;
                    incom_stop_req_timeout  <= 1'b1;
                end
                else
                begin
                    dword_cnt   <= dword_cnt + 1'b1;
                    state       <= STATE_IN_UNRECOG;
                end
                    
1103 1104 1105 1106 1107 1108 1109
            end

            default:
            begin
            end
        endcase

1110 1111 1112 1113 1114 1115
// buys circuit
assign  cmd_busy = |state | frame_busy;

// respond if received FIS had any meaning in terms of TL
// actual response shall come next tick after done signal to fit LL fsm
reg incom_done_r;
Alexey Grebenkin's avatar
Alexey Grebenkin committed
1116 1117 1118
reg incom_done_bad_r;
always @ (posedge clk)
    incom_done_bad_r <= incom_done & state == STATE_IN_UNRECOG;
1119
always @ (posedge clk)
Alexey Grebenkin's avatar
Alexey Grebenkin committed
1120 1121 1122
    incom_done_r     <= incom_done;

assign  incom_ack_bad   = incom_done_bad_r | bad_fis_received;
1123 1124 1125 1126 1127 1128
assign  incom_ack_good  = incom_done_r & ~incom_ack_bad;

// after a device says it received the FIS, reveal the error code
assign  cmd_done_good = state == STATE_OUT_WAIT_RESP & frame_done_good;
assign  cmd_done_bad  = state == STATE_OUT_WAIT_RESP & frame_done_bad;

1129 1130 1131
// Reg H2D FIS header
wire    [31:0] header_regfis;
assign  header_regfis   = dword_cnt[2:0] == 3'h0 ?  {sh_feature_in[7:0], sh_command_in, cmd_type_r == CMD_TYPE_REG_CMD, 3'h0, cmd_port_r, 8'h27} : //  features command C R R R PMPort FISType
1132
                          dword_cnt[2:0] == 3'h1 ?  {sh_dev_in, sh_lba_in[39:32], sh_lba_in[23:16], sh_lba_in[7:0]} : // Device LBAHigh LBAMid LBALow
1133 1134 1135 1136 1137
                          dword_cnt[2:0] == 3'h2 ?  {sh_feature_in[15:8], sh_lba_in[47:40], sh_lba_in[31:24], sh_lba_in[15:8]} : // Features (exp) LBAHigh (exp) LBAMid (exp) LBALow (exp)
                          dword_cnt[2:0] == 3'h3 ?  {sh_control_in[7:0], 8'h00, sh_count_in[15:0]} : // Control Reserved SectorCount (exp) SectorCount
                       /*dword_cnt[2:0] == 3'h4 ?*/ {32'h0000}; // Reserved
// DMA Setup FIS header
wire    [31:0] header_dmas;
1138 1139 1140 1141 1142 1143
assign  header_dmas     = dword_cnt[3:0] == 4'h0 ?  {8'h0, 8'h0, sh_autoact_in, sh_inter_in, sh_dir_in, 1'b0, cmd_port_r, 8'h41} : // Reserved, Reserved, A I D R PMPort, FIS Type
                          dword_cnt[3:0] == 4'h1 ?  {sh_dma_id_in[31:0]} : // DMA Buffer Identifier Low
                          dword_cnt[3:0] == 4'h2 ?  {sh_dma_id_in[63:32]} : // DMA Buffer Identifier High
                          dword_cnt[3:0] == 4'h4 ?  {sh_buf_off_in[31:0]} : // DMA Buffer Offset
                          dword_cnt[3:0] == 4'h5 ?  {sh_dma_cnt_in[31:0]} : // DMA Transfer Count
                                  /* 4'h3 | 4'h6 */ {32'h0000}; // Reserved
1144 1145
// BIST Activate FIS header
wire    [31:0] header_bist; // TODO
1146 1147 1148
assign  header_bist     = dword_cnt[2:0] == 3'h0 ?  {8'h00, 8'h00, 4'h0, cmd_port_r, 8'h58} : // Reserved, T A S L F P R V, R R R R PMPort, FIS Type
                          dword_cnt[2:0] == 3'h1 ?  {32'h00000000} : // Data1
                          dword_cnt[2:0] == 3'h2 ?  {32'h00000000} : // Data2
1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165
                                                    {32'h00000000};
// Data FIS header
wire    [31:0] header_data;
assign  header_data     = {8'h00, 8'h00, 4'h0, cmd_port_r, 8'h46}; // Reserved, Reserved, R R R R PMPort, FIS Type


assign  ll_header_val   = state == STATE_OUT_REG | state == STATE_OUT_DMAS | state == STATE_OUT_BIST | state == STATE_OUT_DATA_H; 
assign  ll_header_last  = state == STATE_OUT_REG    & dword_cnt[2:0] == 3'h4 |
                          state == STATE_OUT_DMAS   & dword_cnt[2:0] == 3'h6 |
                          state == STATE_OUT_BIST   & dword_cnt[2:0] == 3'h2;
assign  ll_header_dword = {32{state == STATE_OUT_REG}}      & header_regfis | 
                          {32{state == STATE_OUT_DMAS}}     & header_dmas   | 
                          {32{state == STATE_OUT_BIST}}     & header_bist   |
                          {32{state == STATE_OUT_DATA_H}}   & header_data;

// bypass data from ll to cl if it's data stage in data FIS
assign  cl_data_val_out     = ll_data_val_in & state == STATE_IN_DATA;
1166
assign  cl_data_last_out    = ll_data_val_in & ll_data_last_in & state == STATE_IN_DATA;
1167 1168
assign  cl_data_mask_out    = ll_data_mask_in;
assign  cl_data_out         = ll_data_in & {32{cl_data_val_out}};
Alexey Grebenkin's avatar
Alexey Grebenkin committed
1169
assign  ll_data_busy_out    = cl_data_busy_in;
1170 1171

// set data to ll: bypass payload from cl or headers constructed in here
1172
assign  ll_data_val_out     = ll_header_val | cl_data_val_in;
1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183
assign  ll_data_last_out    = ll_header_last & ll_header_val | cl_data_last_in & ~ll_header_val; 
assign  ll_data_out         = ll_header_dword & {32{ll_header_val}} | cl_data_in & {32{~ll_header_val}};
assign  ll_data_mask_out    = {2{ll_header_val}} | cl_data_mask_in & {2{~ll_header_val}};

// limit was 2048 words + 1 headers
assign  data_limit_exceeded = dword_cnt == 14'd2048 & ~cl_data_last_in;

// check if no data was obtained from buffer by ll when we're waiting for a response
wire    chk_strobe_while_waitresp;
assign  chk_strobe_while_waitresp = state == STATE_OUT_WAIT_RESP & ll_data_strobe_in;

Alexey Grebenkin's avatar
Alexey Grebenkin committed
1184 1185
// issue a FIS 
assign  frame_req = cmd_val & state == STATE_IDLE & ~frame_busy;
1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222

// update shadow registers as soon as transaction finishes TODO invalidate in case of errors
// TODO update only corresponding fields, which was updated during the transmission
assign  sh_lba_out      = loc_lba;
assign  sh_count_out    = loc_count;
assign  sh_command_out  = loc_command;
assign  sh_err_out      = loc_err;
assign  sh_status_out   = loc_status;
assign  sh_estatus_out  = loc_estatus;
assign  sh_dev_out      = loc_dev;
assign  sh_port_out     = loc_port;
assign  sh_inter_out    = loc_inter;
assign  sh_dir_out      = loc_dir;
assign  sh_dma_id_out   = loc_dma_id;
assign  sh_dma_off_out  = loc_dma_off;
assign  sh_dma_cnt_out  = loc_dma_cnt;
assign  sh_tran_cnt_out = loc_tran_cnt;
assign  sh_notif_out    = loc_notif;
assign  sh_autoact_out  = loc_autoact;

assign  sh_lba_val_out      = ll_data_last_in;
assign  sh_count_val_out    = ll_data_last_in;
assign  sh_command_val_out  = ll_data_last_in;
assign  sh_err_val_out      = ll_data_last_in;
assign  sh_status_val_out   = ll_data_last_in;
assign  sh_estatus_val_out  = ll_data_last_in;
assign  sh_dev_val_out      = ll_data_last_in;
assign  sh_port_val_out     = ll_data_last_in;
assign  sh_inter_val_out    = ll_data_last_in;
assign  sh_dir_val_out      = ll_data_last_in;
assign  sh_dma_id_val_out   = ll_data_last_in;
assign  sh_dma_off_val_out  = ll_data_last_in;
assign  sh_dma_cnt_val_out  = ll_data_last_in;
assign  sh_tran_cnt_val_out = ll_data_last_in;
assign  sh_notif_val_out    = ll_data_last_in;
assign  sh_autoact_val_out  = ll_data_last_in;

1223 1224 1225
// dma activate is received when its type met and no errors occurs
assign  got_dma_activate        = state == STATE_INCOMING & cl_data_last_in & ll_data_val_in & ll_data_in[7:0] == 8'h39;
assign  got_dma_activate_port   = {4{got_dma_activate}} & ll_data_in[11:8];
1226

1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241
`ifdef CHECKERS_ENABLED
always @ (posedge clk)
    if (~rst)
    if (chk_strobe_while_waitresp)
    begin
        $display("ERROR in %m: retrieving data while being in a STATE_OUT_WAIT_RESP state");
        $finish;
    end
`endif

// eof response watchdog
assign  watchdog_eof = dword_cnt == WATCHDOG_EOF_LIMIT & state == STATE_OUT_WAIT_RESP;
`ifdef CHECKERS_ENABLED
always @ (posedge clk)
    if (~rst)
Alexey Grebenkin's avatar
Alexey Grebenkin committed
1242
    if (watchdog_eof)
1243 1244 1245 1246 1247
    begin
        $display("WARNING in %m: watchdog_eof asserted");
        $stop;
    end
`endif
1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258
`ifdef CHECKERS_ENABLED
always @ (posedge clk)
    if (~rst)
    if (watchdog_dwords)
    begin
        $display("ERROR in %m: state %h - current FIS contains more than 2048 dwords", state);
        $finish;
    end
`endif
wire chk_inc_dword_limit_exceeded;
assign  chk_inc_dword_limit_exceeded = state == STATE_IN_DATA & dword_cnt == 14'd2049;
1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269
`ifdef CHECKERS_ENABLED
always @ (posedge clk)
    if (~rst)
    if (chk_inc_dword_limit_exceeded)
    begin
        $display("ERROR in %m: received more than 2048 words in one FIS");
        $finish;
    end
`endif

endmodule