ahci_dma_wr_fifo.v 24.3 KB
Newer Older
1 2 3 4 5 6 7
/*!
 * <b>Module:</b>ahci_dma_wr_fifo
 * @file ahci_dma_wr_fifo.v
 * @date 2016-01-02  
 * @author Andrey Filippov
 *
 * @brief cross clocks,  word-realign, 32 -> 64 with byte write mask
8 9 10
 * Convertion from x32 DWORD data received from FIS-es @ mclk to QWORD-aligned
 * AXI data @hclk
 *
11 12 13 14
 * @copyright Copyright (c) 2016 Elphel, Inc .
 *
 * <b>License:</b>
 *
15 16 17 18 19 20 21 22 23 24 25 26
 * ahci_dma_wr_fifo.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.
 *
 *  ahci_dma_wr_fifo.v 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/> .
27 28 29 30 31 32 33 34 35 36 37 38 39
 *
 * 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.
40
 */
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
`timescale 1ns/1ps

module  ahci_dma_wr_fifo#(
    parameter WCNT_BITS    = 21,
    parameter ADDRESS_BITS = 3
)(
    input                 mrst,
    input                 hrst,
    input                 mclk,
    input                 hclk,
    // hclk domain
    input [WCNT_BITS-1:0] wcnt,  // decrementing word counter, 0- based (0 need 1, 1 - need 2, ...) valid @ start
    input           [1:0] woffs, // 2 LSBs of the initial word address - valid @ start
    input                 init,  // initializes cross-clock 32->64 FIFO, disables FIFO read until confirmed back form mclk domain
    input                 start, // start transfer
    output reg     [63:0] dout, // allow only each 3-rd wr if not many
57
//    input                 dout_av,      // at least one QWORD space avaiable in AXI FIFO
58 59 60 61 62 63 64
    input                 dout_av_many, // several QWORD space avaiable in AXI FIFO
    input                 last_prd, // last prd, flush partial dword if there were odd number of words transferred. valid @ start
    // Or maybe use "last_prd"?
    output                dout_we,
    output reg      [3:0] dout_wstb, // word write enable (apply to wstb,  2 wstb input bits for one dout_wstb bit)
    output reg            done,      // this PRD data sent AXI FIFO (Some partial QWORD data may be left in this module if
                                     // last_prd was not set
65
    output                busy,                                 
66
//    output                done_flush,  // finished last PRD (indicated by last_prd @ start), data left module
67
    output reg            fifo_nempty_mclk, // to detect extra data from FIS, has some latency - only valid after read is stopped
68
    // mclk domain
69
    input          [31:0] din,
70 71 72 73 74 75 76 77 78 79 80 81
    output                din_rdy, // can accept data from HBA (multiple dwords, so reasonable latency is OK)
    input                 din_avail
);
    localparam ADDRESS_NUM = (1<<ADDRESS_BITS); // 8 for ADDRESS_BITS==3
    reg                   [31:0] fifo0_ram  [0: ADDRESS_NUM - 1];
    reg                   [31:0] fifo1_ram  [0: ADDRESS_NUM - 1];
    wire                         init_mclk;
    wire                         init_confirm;
    reg                          en_fifo_rd;
    reg                          en_fifo_wr;
    wire                         flush_hclk; // TODO: Define (less than 4 left to receive)?
    wire                         flush_mclk;
82
//    wire                         flush_conf;
83 84 85 86 87
    reg       [ADDRESS_BITS : 0] raddr; // 1 extra bit       
    reg       [ADDRESS_BITS+1:0] waddr; // 1 extra bit       
    reg                  [63:16] fifo_do_prev; // only 48 bits are needed
    reg  [(1<<ADDRESS_BITS)-1:0] fifo_full;  // set in write clock domain
    reg  [(1<<ADDRESS_BITS)-1:0] fifo_nempty;// set in read clock domain
88
    wire                         fifo_wr = en_fifo_wr && ((din_avail && din_rdy) || (waddr[0] && flush_mclk)); // flush may add extra write of junk
89
//    wire                         fifo_rd;
90
    wire [(1<<ADDRESS_BITS)-1:0] fifo_full2 = {~fifo_full[0],fifo_full[ADDRESS_NUM-1:1]};
91 92
    reg                          hrst_mclk;
    reg                          fifo_dav;  // @hclk
93
    reg                          fifo_dav2; // @hclk - ??? at least two are available?
94
    reg                          fifo_half_mclk; // Half Fifo is empty, OK to write
95 96
/// wire                  [63:0] fifo_do =       {fifo1_ram [raddr[ADDRESS_BITS:1]], fifo0_ram [raddr[ADDRESS_BITS:1]]};
    wire                  [63:0] fifo_do =       {fifo1_ram [raddr[ADDRESS_BITS-1:0]], fifo0_ram [raddr[ADDRESS_BITS-1:0]]};
97
    wire                         dout_we_w;
98 99 100 101 102 103 104 105 106 107 108
    reg                    [1:0] dout_we_r;
    
    reg                    [1:0] wp;   // word pointer in the output (0..3)
    reg                    [1:0] fp;   // pointer in the  {fifo_do,fifo_do_prev} pointer (0 - fifo_do_prev[16], ..., 3 - fifo_do[0])
    reg                    [1:0] wl;   // words left: 0: 1 word, ..., 3: >=4 words
    // implementing 6 -> 23 unregistered ROM
    reg                    [1:0] mx0; //4:1
    reg                    [2:0] mx1; //5:1
    reg                    [2:0] mx2; //6:1
    reg                    [2:0] mx3; //7:1
    reg                    [3:0] pm; // re_dout_wstb;
109 110
    wire                         fifo_rd;
    reg                          fifo_rd_r;
111 112 113
//    reg                    [1:0] nwp; // Needed? 0 for all but first
    reg                    [1:0] nfp; //  next {fifo_do,fifo_do_prev} pointer (0 - fifo_do_prev[16], ..., 3 - fifo_do[0])
    reg                    [2:0] swl;  // subtract from words_left;
114
    reg                          need_fifo; // needs reading fifo
115
    // TODO: make separate register bits for  wl == 0, wl > =4
116 117 118 119 120 121 122 123 124 125 126 127
    reg                          busy_r;
    reg                          is_last_prd;
    reg          [WCNT_BITS-1:0] wcntr;
    wire         [WCNT_BITS-1:0] next_wcntr = wcntr[WCNT_BITS-1:0] - swl[2:0];
    reg                          flushing;
//    wire                         done_w = dout_we_r[0] && !(next_wcntr[WCNT_BITS];
    wire                         last_qword= !(|wcntr[WCNT_BITS-1:2]) && 
                                               ((wcntr[1:0] == 0) ||
                                                 swl[2] ||
                                                 (!wcntr[1] && swl[1]) ||
                                                 (!wcntr[0] && (&swl[1:0])) );
    wire                         done_w = dout_we_w && last_qword;
128
    
129 130
//    wire                         axi_ready = dout_av && (dout_av_many || (!dout_we_r));
    wire                         axi_ready = dout_av_many;
131 132

    wire                         fifo_out_ready = en_fifo_rd && (!need_fifo || (fifo_dav && (fifo_dav2 || !fifo_rd_r)));
133
    
134 135
///    assign flush_hclk = is_last_prd && !flushing && !nfp[1] && last_qword && waddr[0]; // waddr[0] - other clock domain, but OK here,
    assign flush_hclk = busy && is_last_prd && !flushing && !nfp[1] && last_qword && waddr[0]; // waddr[0] - other clock domain, but OK here,
136
    // it was last 1->0 before previous FIFO read. flush_hclk will only be generated for odd number of dwords
137 138
    
    assign din_rdy = en_fifo_wr && fifo_half_mclk;
139 140 141 142 143 144
    assign dout_we = dout_we_r[0]; // dout_we_r[0] - write to dout, use dout_av && (!(|dout_we_r) || dout_av_many) to enable dout_we_r[0]<=
    assign busy = busy_r || dout_we_r[0];
    
    assign dout_we_w = axi_ready && fifo_out_ready && busy_r;
    assign fifo_rd =   dout_we_w && need_fifo;
    
145
    always @ (posedge hclk) begin
146 147 148 149 150 151 152 153 154 155
        if      (hrst || init)          en_fifo_rd <= 0;
        else if (init_confirm)          en_fifo_rd <= 1;
        else if (done_w && is_last_prd) en_fifo_rd <= 0;
        
        done <=      done_w;
        
        fifo_rd_r <= fifo_rd;
        
        
        if (hrst || init)               raddr <= 0;
156
        else if (fifo_rd)               raddr <= raddr + 1; // increment for 64-bit words
157 158 159
        
        //    reg       [ADDRESS_BITS : 0] raddr; // 1 extra bit       
        
160 161

        if      (hrst || init)        fifo_nempty <= {{(ADDRESS_NUM>>1){1'b0}},{(ADDRESS_NUM>>1){1'b1}}};// 8'b00001111
162 163
///        else if (fifo_rd && raddr[0]) fifo_nempty <= {fifo_nempty[ADDRESS_NUM-2:0],raddr[ADDRESS_BITS] ^ raddr[ADDRESS_BITS-1]};
        else if (fifo_rd)             fifo_nempty <= {fifo_nempty[ADDRESS_NUM-2:0],~raddr[ADDRESS_BITS] ^ raddr[ADDRESS_BITS-1]};
164 165

        
166 167 168 169
///     fifo_dav <=  !init && en_fifo_rd && (fifo_full [raddr[ADDRESS_BITS:1]] ^ raddr[ADDRESS_BITS]);
        fifo_dav <=  !init && en_fifo_rd && (fifo_full [raddr[ADDRESS_BITS-1:0]] ^ raddr[ADDRESS_BITS]);
///     fifo_dav2 <= !init && en_fifo_rd && (fifo_full2[raddr[ADDRESS_BITS:1]]); //?^ raddr[ADDRESS_BITS]); // FIXME
        fifo_dav2 <= !init && en_fifo_rd && (fifo_full2[raddr[ADDRESS_BITS-1:0]] ^ raddr[ADDRESS_BITS]); //?^ raddr[ADDRESS_BITS]); // FIXME
170 171

        if (fifo_rd) fifo_do_prev[63:16] <= fifo_do[63:16];
172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241
        
        if      (start)      is_last_prd <= last_prd;

        // flushing will only be set for the last dword in last PRD if total number of dwords is ODD.
        // Odd number of words should be handled outside of this module (before) 
        if  (hrst || init || start)  flushing <= 0;
        else if (flush_hclk)         flushing <= 1;
        else if (done_w)             flushing <= 0;

        if (hrst || init)            busy_r <= 0;
        else if (start)              busy_r <= 1;
        else if (done_w)             busy_r <= 0;
        
        dout_we_r <= {dout_we_r[0], dout_we_w};
        
        if      (start)     wcntr <= wcnt;
        else if (dout_we_w) wcntr <= next_wcntr; // wcntr - swl[2:0];
        
        if      (start)     wp <= woffs;
        else if (dout_we_w) wp <= 0; // all but possibly wirst QWORD are aligned to th low word
        
        if      (init)       fp <= 3;    // only reset for the first PRD, points to the beginning of the fifo_do (fifo_do_prev - empty)
        else if (dout_we_w)  fp <= nfp;
        
        // words left: 0: 1 word, ..., 3: >=4 words
        if      (start)     wl <= wcnt[1:0] |        {2{|wcnt[WCNT_BITS-1:2]}};
        else if (dout_we_w) wl <= next_wcntr[1:0]  | {2{|wcntr[WCNT_BITS-1:3] | next_wcntr[2]}};
        
        if (dout_we_w) begin
            dout_wstb <= pm;
        
            case (mx0)
                2'h0: dout[15: 0] <= fifo_do_prev[31:16];
                2'h1: dout[15: 0] <= fifo_do_prev[47:32];
                2'h2: dout[15: 0] <= fifo_do_prev[63:48];
                2'h3: dout[15: 0] <= fifo_do     [15: 0];
            endcase

            case (mx1)
                3'h0: dout[31:16] <= fifo_do_prev[31:16];
                3'h1: dout[31:16] <= fifo_do_prev[47:32];
                3'h2: dout[31:16] <= fifo_do_prev[63:48];
                3'h3: dout[31:16] <= fifo_do     [15: 0];
                3'h4: dout[31:16] <= fifo_do     [31:16];
                default: dout[31:16] <= 16'bx; // should never get here
            endcase

            case (mx2)
                3'h0: dout[47:32] <= fifo_do_prev[31:16];
                3'h1: dout[47:32] <= fifo_do_prev[47:32];
                3'h2: dout[47:32] <= fifo_do_prev[63:48];
                3'h3: dout[47:32] <= fifo_do     [15: 0];
                3'h4: dout[47:32] <= fifo_do     [31:16];
                3'h5: dout[47:32] <= fifo_do     [47:32];
                default: dout[47:32] <= 16'bx; // should never get here
            endcase

            case (mx3)
                3'h0: dout[63:48] <= fifo_do_prev[31:16];
                3'h1: dout[63:48] <= fifo_do_prev[47:32];
                3'h2: dout[63:48] <= fifo_do_prev[63:48];
                3'h3: dout[63:48] <= fifo_do     [15: 0];
                3'h4: dout[63:48] <= fifo_do     [31:16];
                3'h5: dout[63:48] <= fifo_do     [47:32];
                3'h6: dout[63:48] <= fifo_do     [63:48];
                default: dout[63:48] <= 16'bx; // should never get here
            endcase

        end
        
242
    end
243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259
 /*
 
     output reg     [63:0] dout, // allow only each 3-rd wr if not many
    input                 dout_av,      // at least one QWORD space avaiable in AXI FIFO
    input                 dout_av_many, // several QWORD space avaiable in AXI FIFO
    input                 last_prd, // last prd, flush partial dword if there were odd number of words transferred. valid @ start
    // Or maybe use "last_prd"?
    output                dout_we,
    output reg      [3:0] dout_wstb, // word write enable (apply to wstb,  2 wstb input bits for one dout_wstb bit)
    output reg            done,      // this PRD data sent AXI FIFO (Some partial QWORD data may be left in this module if
 
  wl3[2:0]
  
     always @* case ({wp, fp, wl})
        6'h00: begin mx0 <= 0; mx1 <= 1; mx2 <= 2; mx3  <= 3; pm <= 4'b0001; fifo_rd <= 0; nfp <= 1; swl <= 1; end
 
 */   
260 261 262 263 264 265 266 267 268 269 270 271 272 273

    // mclk domain
    always @ (posedge mclk) begin
        hrst_mclk <= hrst;

        if      (mrst || hrst_mclk) en_fifo_wr <= 0;
        else if (init_mclk)         en_fifo_wr <= 1;
        else if (flush_mclk)        en_fifo_wr <= 0;


        if (hrst_mclk || init_mclk)    waddr <= 0;
        else if (fifo_wr)              waddr <= waddr + 1; 
        
        if (hrst_mclk || init_mclk)    fifo_full <= 0;
274 275
///     else if (fifo_wr) fifo_full <= {fifo_full[ADDRESS_NUM-2:0], waddr[ADDRESS_BITS+1]};
        else if (fifo_wr && waddr[0])  fifo_full <= {fifo_full[ADDRESS_NUM-2:0], ~waddr[ADDRESS_BITS+1]};
276
        
277
        fifo_half_mclk <= en_fifo_wr && fifo_nempty [waddr[ADDRESS_BITS:1]] ^ waddr[ADDRESS_BITS+1];
278 279 280 281
        
        if (fifo_wr && !waddr[0]) fifo0_ram[waddr[ADDRESS_BITS:1]] <= din;
        if (fifo_wr &&  waddr[0]) fifo1_ram[waddr[ADDRESS_BITS:1]] <= din;
        
282 283
///     fifo_nempty_mclk <= (fifo_full [raddr[ADDRESS_BITS:1]] ^ raddr[ADDRESS_BITS]); // only valid after read is stopped
        fifo_nempty_mclk <= (fifo_full [raddr[ADDRESS_BITS-1:0]] ^ raddr[ADDRESS_BITS]); // only valid after read is stopped
284
        
285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321
    end


    // hclk -> mclk cross-clock synchronization
    pulse_cross_clock #(
        .EXTRA_DLY(0)
    ) init_mclk_i (
        .rst       (hrst),            // input
        .src_clk   (hclk),            // input
        .dst_clk   (mclk),            // input
        .in_pulse  (init),            // input
        .out_pulse (init_mclk),       // output
        .busy()                       // output
    );

    pulse_cross_clock #(
        .EXTRA_DLY(0)
    ) flush_mclk_i (
        .rst       (hrst),            // input
        .src_clk   (hclk),            // input
        .dst_clk   (mclk),            // input
        .in_pulse  (flush_hclk),      // input
        .out_pulse (flush_mclk),      // output
        .busy()                       // output
    );

    // mclk -> hclk cross-clock synchronization
    pulse_cross_clock #(
        .EXTRA_DLY(0)
    ) init_confirm_i (
        .rst       (mrst),            // input
        .src_clk   (mclk),            // input
        .dst_clk   (hclk),            // input
        .in_pulse  (init_mclk),       // input
        .out_pulse (init_confirm),    // output
        .busy()                       // output
    );
322
/*
323 324 325 326 327 328 329 330 331 332
    pulse_cross_clock #(
        .EXTRA_DLY(0)
    ) flush_conf_i (
        .rst       (mrst),            // input
        .src_clk   (mclk),            // input
        .dst_clk   (hclk),            // input
        .in_pulse  (flush_mclk),      // input
        .out_pulse (flush_conf),      // output
        .busy()                       // output
    );
333
*/
334 335 336 337 338 339 340 341 342 343 344
    /*
    wl: 0: left 1 word, 1: left 2 words, 2: left 3 words, 3: left >=4 words
    wp (pointer in the output qword, only first in PRD can be non-zero) 0: word 0 of output QW, ...
    mx0 0: use fifo_do_prev[16], 1: fifo_do_prev[32], 2:fifo_do_prev[48], 3:fifo_do[0];
    mx1 0: use fifo_do_prev[16], 1: fifo_do_prev[32], 2:fifo_do_prev[48], 3:fifo_do[0], 4:fifo_do[16];
    mx2 0: use fifo_do_prev[16], 1: fifo_do_prev[32], 2:fifo_do_prev[48], 3:fifo_do[0], 4:fifo_do[16], 5:fifo_do[32];
    mx3 0: use fifo_do_prev[16], 1: fifo_do_prev[32], 2:fifo_do_prev[48], 3:fifo_do[0], 4:fifo_do[16], 5:fifo_do[32],  6:fifo_do[48];
    fp/nfp: 0 - pointer to fifo_do_prev[16], 1 : fifo_do_prev[32], 2: fifo_do_prev[48], 3: fifo_do[0]
    
    */
    always @* case ({wp, fp, wl})
345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378
        6'h00: begin mx0 <= 0; mx1 <= 1; mx2 <= 2; mx3  <= 3; pm <= 4'b0001; need_fifo <= 0; nfp <= 1; swl <= 1; end
        6'h01: begin mx0 <= 0; mx1 <= 1; mx2 <= 2; mx3  <= 3; pm <= 4'b0011; need_fifo <= 0; nfp <= 2; swl <= 2; end
        6'h02: begin mx0 <= 0; mx1 <= 1; mx2 <= 2; mx3  <= 3; pm <= 4'b0111; need_fifo <= 0; nfp <= 3; swl <= 3; end
        6'h03: begin mx0 <= 0; mx1 <= 1; mx2 <= 2; mx3  <= 3; pm <= 4'b1111; need_fifo <= 1; nfp <= 0; swl <= 4; end

        6'h04: begin mx0 <= 1; mx1 <= 2; mx2 <= 3; mx3  <= 4; pm <= 4'b0001; need_fifo <= 0; nfp <= 2; swl <= 1; end
        6'h05: begin mx0 <= 1; mx1 <= 2; mx2 <= 3; mx3  <= 4; pm <= 4'b0011; need_fifo <= 0; nfp <= 3; swl <= 2; end
        6'h06: begin mx0 <= 1; mx1 <= 2; mx2 <= 3; mx3  <= 4; pm <= 4'b0111; need_fifo <= 1; nfp <= 0; swl <= 3; end
        6'h07: begin mx0 <= 1; mx1 <= 2; mx2 <= 3; mx3  <= 4; pm <= 4'b1111; need_fifo <= 1; nfp <= 1; swl <= 4; end

        6'h08: begin mx0 <= 2; mx1 <= 3; mx2 <= 4; mx3  <= 5; pm <= 4'b0001; need_fifo <= 0; nfp <= 3; swl <= 1; end
        6'h09: begin mx0 <= 2; mx1 <= 3; mx2 <= 4; mx3  <= 5; pm <= 4'b0011; need_fifo <= 1; nfp <= 0; swl <= 2; end
        6'h0a: begin mx0 <= 2; mx1 <= 3; mx2 <= 4; mx3  <= 5; pm <= 4'b0111; need_fifo <= 1; nfp <= 1; swl <= 3; end
        6'h0b: begin mx0 <= 2; mx1 <= 3; mx2 <= 4; mx3  <= 5; pm <= 4'b1111; need_fifo <= 1; nfp <= 2; swl <= 4; end

        6'h0c: begin mx0 <= 3; mx1 <= 4; mx2 <= 5; mx3  <= 6; pm <= 4'b0001; need_fifo <= 1; nfp <= 0; swl <= 1; end
        6'h0d: begin mx0 <= 3; mx1 <= 4; mx2 <= 5; mx3  <= 6; pm <= 4'b0011; need_fifo <= 1; nfp <= 1; swl <= 2; end
        6'h0e: begin mx0 <= 3; mx1 <= 4; mx2 <= 5; mx3  <= 6; pm <= 4'b0111; need_fifo <= 1; nfp <= 2; swl <= 3; end
        6'h0f: begin mx0 <= 3; mx1 <= 4; mx2 <= 5; mx3  <= 6; pm <= 4'b1111; need_fifo <= 1; nfp <= 3; swl <= 4; end

        6'h10: begin mx0 <= 0; mx1 <= 0; mx2 <= 1; mx3  <= 2; pm <= 4'b0010; need_fifo <= 0; nfp <= 1; swl <= 1; end
        6'h11: begin mx0 <= 0; mx1 <= 0; mx2 <= 1; mx3  <= 2; pm <= 4'b0110; need_fifo <= 0; nfp <= 2; swl <= 2; end
        6'h12: begin mx0 <= 0; mx1 <= 0; mx2 <= 1; mx3  <= 2; pm <= 4'b1110; need_fifo <= 0; nfp <= 3; swl <= 3; end
        6'h13: begin mx0 <= 0; mx1 <= 0; mx2 <= 1; mx3  <= 2; pm <= 4'b1110; need_fifo <= 0; nfp <= 3; swl <= 3; end

        6'h14: begin mx0 <= 0; mx1 <= 1; mx2 <= 2; mx3  <= 3; pm <= 4'b0010; need_fifo <= 0; nfp <= 2; swl <= 1; end
        6'h15: begin mx0 <= 0; mx1 <= 1; mx2 <= 2; mx3  <= 3; pm <= 4'b0110; need_fifo <= 0; nfp <= 3; swl <= 2; end
        6'h16: begin mx0 <= 0; mx1 <= 1; mx2 <= 2; mx3  <= 3; pm <= 4'b1110; need_fifo <= 1; nfp <= 0; swl <= 3; end
        6'h17: begin mx0 <= 0; mx1 <= 1; mx2 <= 2; mx3  <= 3; pm <= 4'b1110; need_fifo <= 1; nfp <= 0; swl <= 3; end

        6'h18: begin mx0 <= 1; mx1 <= 2; mx2 <= 3; mx3  <= 4; pm <= 4'b0010; need_fifo <= 0; nfp <= 3; swl <= 1; end
        6'h19: begin mx0 <= 1; mx1 <= 2; mx2 <= 3; mx3  <= 4; pm <= 4'b0110; need_fifo <= 1; nfp <= 0; swl <= 2; end
        6'h1a: begin mx0 <= 1; mx1 <= 2; mx2 <= 3; mx3  <= 4; pm <= 4'b1110; need_fifo <= 1; nfp <= 1; swl <= 3; end
        6'h1b: begin mx0 <= 1; mx1 <= 2; mx2 <= 3; mx3  <= 4; pm <= 4'b1110; need_fifo <= 1; nfp <= 1; swl <= 3; end
379
        
380 381 382 383
        6'h1c: begin mx0 <= 2; mx1 <= 3; mx2 <= 4; mx3  <= 5; pm <= 4'b0010; need_fifo <= 1; nfp <= 0; swl <= 1; end
        6'h1d: begin mx0 <= 2; mx1 <= 3; mx2 <= 4; mx3  <= 5; pm <= 4'b0110; need_fifo <= 1; nfp <= 1; swl <= 2; end
        6'h1e: begin mx0 <= 2; mx1 <= 3; mx2 <= 4; mx3  <= 5; pm <= 4'b1110; need_fifo <= 1; nfp <= 2; swl <= 3; end
        6'h1f: begin mx0 <= 2; mx1 <= 3; mx2 <= 4; mx3  <= 5; pm <= 4'b1110; need_fifo <= 1; nfp <= 2; swl <= 3; end
384
        
385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408
        6'h20: begin mx0 <= 0; mx1 <= 0; mx2 <= 0; mx3  <= 1; pm <= 4'b0100; need_fifo <= 0; nfp <= 1; swl <= 1; end
        6'h21: begin mx0 <= 0; mx1 <= 0; mx2 <= 0; mx3  <= 1; pm <= 4'b1100; need_fifo <= 0; nfp <= 2; swl <= 2; end
        6'h22: begin mx0 <= 0; mx1 <= 0; mx2 <= 0; mx3  <= 1; pm <= 4'b1100; need_fifo <= 0; nfp <= 2; swl <= 2; end
        6'h23: begin mx0 <= 0; mx1 <= 0; mx2 <= 0; mx3  <= 1; pm <= 4'b1100; need_fifo <= 0; nfp <= 2; swl <= 2; end

        6'h24: begin mx0 <= 0; mx1 <= 0; mx2 <= 1; mx3  <= 2; pm <= 4'b0100; need_fifo <= 0; nfp <= 2; swl <= 1; end
        6'h25: begin mx0 <= 0; mx1 <= 0; mx2 <= 1; mx3  <= 2; pm <= 4'b1100; need_fifo <= 0; nfp <= 3; swl <= 2; end
        6'h26: begin mx0 <= 0; mx1 <= 0; mx2 <= 1; mx3  <= 2; pm <= 4'b1100; need_fifo <= 0; nfp <= 3; swl <= 2; end
        6'h27: begin mx0 <= 0; mx1 <= 0; mx2 <= 1; mx3  <= 2; pm <= 4'b1100; need_fifo <= 0; nfp <= 3; swl <= 2; end

        6'h28: begin mx0 <= 0; mx1 <= 1; mx2 <= 2; mx3  <= 3; pm <= 4'b0100; need_fifo <= 0; nfp <= 3; swl <= 1; end
        6'h29: begin mx0 <= 0; mx1 <= 1; mx2 <= 2; mx3  <= 3; pm <= 4'b1100; need_fifo <= 1; nfp <= 0; swl <= 2; end
        6'h2a: begin mx0 <= 0; mx1 <= 1; mx2 <= 2; mx3  <= 3; pm <= 4'b1100; need_fifo <= 1; nfp <= 0; swl <= 2; end
        6'h2b: begin mx0 <= 0; mx1 <= 1; mx2 <= 2; mx3  <= 3; pm <= 4'b1100; need_fifo <= 1; nfp <= 0; swl <= 2; end

        6'h2c: begin mx0 <= 1; mx1 <= 2; mx2 <= 3; mx3  <= 4; pm <= 4'b0100; need_fifo <= 1; nfp <= 0; swl <= 1; end
        6'h2d: begin mx0 <= 1; mx1 <= 2; mx2 <= 3; mx3  <= 4; pm <= 4'b1100; need_fifo <= 1; nfp <= 1; swl <= 2; end
        6'h2e: begin mx0 <= 1; mx1 <= 2; mx2 <= 3; mx3  <= 4; pm <= 4'b1100; need_fifo <= 1; nfp <= 1; swl <= 2; end
        6'h2f: begin mx0 <= 1; mx1 <= 2; mx2 <= 3; mx3  <= 4; pm <= 4'b1100; need_fifo <= 1; nfp <= 1; swl <= 2; end

        6'h30: begin mx0 <= 0; mx1 <= 0; mx2 <= 0; mx3  <= 0; pm <= 4'b1000; need_fifo <= 0; nfp <= 1; swl <= 1; end
        6'h31: begin mx0 <= 0; mx1 <= 0; mx2 <= 0; mx3  <= 0; pm <= 4'b1000; need_fifo <= 0; nfp <= 1; swl <= 1; end
        6'h32: begin mx0 <= 0; mx1 <= 0; mx2 <= 0; mx3  <= 0; pm <= 4'b1000; need_fifo <= 0; nfp <= 1; swl <= 1; end
        6'h33: begin mx0 <= 0; mx1 <= 0; mx2 <= 0; mx3  <= 0; pm <= 4'b1000; need_fifo <= 0; nfp <= 1; swl <= 1; end
409
        
410 411 412 413 414 415 416 417 418 419 420 421 422 423
        6'h34: begin mx0 <= 0; mx1 <= 0; mx2 <= 0; mx3  <= 1; pm <= 4'b1000; need_fifo <= 0; nfp <= 2; swl <= 1; end
        6'h35: begin mx0 <= 0; mx1 <= 0; mx2 <= 0; mx3  <= 1; pm <= 4'b1000; need_fifo <= 0; nfp <= 2; swl <= 1; end
        6'h36: begin mx0 <= 0; mx1 <= 0; mx2 <= 0; mx3  <= 1; pm <= 4'b1000; need_fifo <= 0; nfp <= 2; swl <= 1; end
        6'h37: begin mx0 <= 0; mx1 <= 0; mx2 <= 0; mx3  <= 1; pm <= 4'b1000; need_fifo <= 0; nfp <= 2; swl <= 1; end

        6'h38: begin mx0 <= 0; mx1 <= 0; mx2 <= 1; mx3  <= 2; pm <= 4'b1000; need_fifo <= 0; nfp <= 3; swl <= 1; end
        6'h39: begin mx0 <= 0; mx1 <= 0; mx2 <= 1; mx3  <= 2; pm <= 4'b1000; need_fifo <= 0; nfp <= 3; swl <= 1; end
        6'h3a: begin mx0 <= 0; mx1 <= 0; mx2 <= 1; mx3  <= 2; pm <= 4'b1000; need_fifo <= 0; nfp <= 3; swl <= 1; end
        6'h3b: begin mx0 <= 0; mx1 <= 0; mx2 <= 1; mx3  <= 2; pm <= 4'b1000; need_fifo <= 0; nfp <= 3; swl <= 1; end

        6'h3c: begin mx0 <= 0; mx1 <= 1; mx2 <= 2; mx3  <= 3; pm <= 4'b1000; need_fifo <= 1; nfp <= 0; swl <= 1; end
        6'h3d: begin mx0 <= 0; mx1 <= 1; mx2 <= 2; mx3  <= 3; pm <= 4'b1000; need_fifo <= 1; nfp <= 0; swl <= 1; end
        6'h3e: begin mx0 <= 0; mx1 <= 1; mx2 <= 2; mx3  <= 3; pm <= 4'b1000; need_fifo <= 1; nfp <= 0; swl <= 1; end
        6'h3f: begin mx0 <= 0; mx1 <= 1; mx2 <= 2; mx3  <= 3; pm <= 4'b1000; need_fifo <= 1; nfp <= 0; swl <= 1; end
424 425 426 427
    endcase

endmodule