cmd_deser.v 13.2 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11
/*!
 * <b>Module:</b>cmd_deser
 * @file cmd_deser.v
 * @date 2015-01-12  
 * @author Andrey Filippov     
 *
 * @brief Expand command address/data from a byte-wide
 *
 * @copyright Copyright (c) 2015 Elphel, Inc.
 *
 * <b>License:</b>
12 13 14 15 16 17 18 19 20 21 22 23 24
 *
 * cmd_deser.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.
 *
 *  cmd_deser.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/> .
25 26 27 28 29 30
 *
 * 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"
31
 * files and/or simulating the code, the copyright holders of this Program give
32 33
 * 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
Andrey Filippov's avatar
Andrey Filippov committed
34
 * charge, and there is no dependence on any encrypted modules for simulating of
35 36 37
 * 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.
38
 */
39 40 41 42
`timescale 1ns/1ps

module  cmd_deser#(
    parameter ADDR=0,
43 44 45 46 47 48 49 50 51
    parameter ADDR_MASK =  'hffff,
    parameter NUM_CYCLES =  6,
    parameter ADDR_WIDTH =  16,
    parameter DATA_WIDTH =  32,
    parameter ADDR1 =       0,   // optional second address
    parameter ADDR_MASK1 =  0,   // optional second mask
    parameter ADDR2 =       0,   // optional third address 
    parameter ADDR_MASK2 =  0,   // optional third mask
    parameter WE_EARLY =    0    // if 1 - we and addr will be valid 1 cycle before data
52
)(
53 54
    input                                               rst,
    input                                               clk,
Andrey Filippov's avatar
Andrey Filippov committed
55
    input                                               srst, // sync reset
56 57 58 59 60
    input                                         [7:0] ad,
    input                                               stb,
    output                             [ADDR_WIDTH-1:0] addr,
    output                             [DATA_WIDTH-1:0] data,
    output [(ADDR_MASK2!=0)?2:((ADDR_MASK1!=0)?1:0):0]  we
61
);
62
    localparam  WE_WIDTH=(ADDR_MASK2!=0)?3:((ADDR_MASK1!=0)?2:1);
63 64 65
    generate
        if (NUM_CYCLES==1)
            cmd_deser_single # (
66 67 68 69 70 71 72 73
                .ADDR       (ADDR),
                .ADDR_MASK  (ADDR_MASK),
                .ADDR_WIDTH (ADDR_WIDTH),
                .DATA_WIDTH (DATA_WIDTH),
                .ADDR1      (ADDR1),
                .ADDR_MASK1 (ADDR_MASK1),
                .ADDR2      (ADDR2),
                .ADDR_MASK2 (ADDR_MASK2),
74 75
                .WE_WIDTH   (WE_WIDTH),
                .WE_EARLY   (WE_EARLY)
76 77 78
            ) i_cmd_deser_single (
                .rst(rst),
                .clk(clk),
Andrey Filippov's avatar
Andrey Filippov committed
79
                .srst(srst),
80 81 82 83 84 85 86 87 88 89 90
                .ad(ad),
                .stb(stb),
                .addr(addr),
                .data(data),
                .we(we)
            );
        else if (NUM_CYCLES==2)
            cmd_deser_dual # (
                .ADDR(ADDR),
                .ADDR_MASK(ADDR_MASK),
                .ADDR_WIDTH(ADDR_WIDTH),
91 92 93 94 95
                .DATA_WIDTH(DATA_WIDTH),
                .ADDR1      (ADDR1),
                .ADDR_MASK1 (ADDR_MASK1),
                .ADDR2      (ADDR2),
                .ADDR_MASK2 (ADDR_MASK2),
96 97
                .WE_WIDTH   (WE_WIDTH),
                .WE_EARLY   (WE_EARLY)
Andrey Filippov's avatar
Andrey Filippov committed
98
            ) i_cmd_deser_dual (
99 100
                .rst(rst),
                .clk(clk),
Andrey Filippov's avatar
Andrey Filippov committed
101
                .srst(srst),
102 103 104 105 106 107 108 109 110 111 112 113
                .ad(ad),
                .stb(stb),
                .addr(addr),
                .data(data),
                .we(we)
            );
        else 
            cmd_deser_multi # (
                .ADDR(ADDR),
                .ADDR_MASK(ADDR_MASK),
                .NUM_CYCLES(NUM_CYCLES),
                .ADDR_WIDTH(ADDR_WIDTH),
114 115 116 117 118
                .DATA_WIDTH(DATA_WIDTH),
                .ADDR1      (ADDR1),
                .ADDR_MASK1 (ADDR_MASK1),
                .ADDR2      (ADDR2),
                .ADDR_MASK2 (ADDR_MASK2),
119 120
                .WE_WIDTH   (WE_WIDTH),
                .WE_EARLY   (WE_EARLY)
Andrey Filippov's avatar
Andrey Filippov committed
121
            ) i_cmd_deser_multi (
122 123
                .rst(rst),
                .clk(clk),
Andrey Filippov's avatar
Andrey Filippov committed
124
                .srst(srst),
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
                .ad(ad),
                .stb(stb),
                .addr(addr),
                .data(data),
                .we(we)
            );
        
    endgenerate

endmodule

module  cmd_deser_single#(
    parameter ADDR=0,
    parameter ADDR_MASK='hffff,
    parameter ADDR_WIDTH=8, // <=8
140 141 142 143 144
    parameter DATA_WIDTH=1,  // will 0 work?
    parameter ADDR1=0,
    parameter ADDR_MASK1=0,
    parameter ADDR2=0,
    parameter ADDR_MASK2=0,
145 146 147
    parameter WE_WIDTH=1,
    parameter WE_EARLY =    0 //
    
148 149 150
)(
    input                   rst,
    input                   clk,
Andrey Filippov's avatar
Andrey Filippov committed
151
    input                   srst, // sync reset
152 153 154 155
    input             [7:0] ad,
    input                   stb,
    output [ADDR_WIDTH-1:0] addr,
    output [DATA_WIDTH-1:0] data,
156
    output  [WE_WIDTH-1:0]  we
157 158 159
);
    localparam  ADDR_LOW= ADDR & 8'hff;
    localparam  ADDR_MASK_LOW= ADDR_MASK & 8'hff;
160 161 162 163
    localparam  ADDR_LOW1= ADDR1 & 8'hff;
    localparam  ADDR_MASK_LOW1= ADDR_MASK1 & 8'hff;
    localparam  ADDR_LOW2= ADDR2 & 8'hff;
    localparam  ADDR_MASK_LOW2= ADDR_MASK2 & 8'hff;
164
    reg                 [7:0] deser_r;
165
    wire                [2:0] match_low;
166
    reg         [2:0]         we_r;
167
    
168
    assign we = (WE_EARLY > 0)?(match_low[WE_WIDTH-1:0] & {WE_WIDTH{stb}}):we_r[WE_WIDTH-1:0];
169 170 171 172
    assign match_low= { // unused bits will be optimized
     ((ad ^ ADDR_LOW2)  & (8'hff & ADDR_MASK_LOW2)) == 0,
     ((ad ^ ADDR_LOW1)  & (8'hff & ADDR_MASK_LOW1)) == 0,
     ((ad ^ ADDR_LOW )  & (8'hff & ADDR_MASK_LOW )) == 0};
173
    always @ (posedge rst or posedge clk) begin
Andrey Filippov's avatar
Andrey Filippov committed
174 175 176 177 178
        if      (rst)  we_r <= 0; 
        else if (srst) we_r <= 0; 
        else           we_r <= match_low & {3{stb}};
        if (rst)      deser_r <= 0; 
        else if (srst) deser_r <= 0; 
179
        else if ((|match_low) && stb) deser_r <= ad;
180 181
    end
    assign data={DATA_WIDTH{1'b0}};
182 183
//    assign addr=deser_r[ADDR_WIDTH-1:0];
    assign addr=(WE_EARLY>0) ? ad[ADDR_WIDTH-1:0]: deser_r[ADDR_WIDTH-1:0];
184 185 186 187 188 189
endmodule

module  cmd_deser_dual#(
    parameter ADDR=0,
    parameter ADDR_MASK='hffff,
    parameter ADDR_WIDTH=12, // <=16
190 191 192 193 194
    parameter DATA_WIDTH=1,  // will 0 work?
    parameter ADDR1=0,
    parameter ADDR_MASK1=0,
    parameter ADDR2=0,
    parameter ADDR_MASK2=0,
195 196
    parameter WE_WIDTH=1,
    parameter WE_EARLY =    0    // if 1 - we and addr will be valid 1 cycle before data
197 198 199
)(
    input                   rst,
    input                   clk,
Andrey Filippov's avatar
Andrey Filippov committed
200
    input                   srst, // sync reset
201 202 203 204
    input             [7:0] ad,
    input                   stb,
    output [ADDR_WIDTH-1:0] addr,
    output [DATA_WIDTH-1:0] data,
205
    output   [WE_WIDTH-1:0] we
206 207 208 209 210
);
    localparam  ADDR_LOW= ADDR & 8'hff;
    localparam  ADDR_HIGH=(ADDR>>8) & 8'hff;
    localparam  ADDR_MASK_LOW= ADDR_MASK & 8'hff;
    localparam  ADDR_MASK_HIGH=(ADDR_MASK>>8) & 8'hff;
211 212 213 214 215 216 217 218 219 220 221 222

    localparam  ADDR_LOW1= ADDR1 & 8'hff;
    localparam  ADDR_MASK_LOW1= ADDR_MASK1 & 8'hff;
    localparam  ADDR_LOW2= ADDR2 & 8'hff;
    localparam  ADDR_MASK_LOW2= ADDR_MASK2 & 8'hff;

    localparam  ADDR_HIGH1=(ADDR1>>8) & 8'hff;
    localparam  ADDR_MASK_HIGH1=(ADDR_MASK1>>8) & 8'hff;
    localparam  ADDR_HIGH2=(ADDR2>>8) & 8'hff;
    localparam  ADDR_MASK_HIGH2=(ADDR_MASK2>>8) & 8'hff;


223
    reg                [15:0] deser_r;
224 225
//    reg                       stb_d;
    reg                 [2:0] stb_d;
226 227
    wire                [2:0] match_low;
    wire                [2:0] match_high;
228 229 230 231 232 233 234

    wire                [2:0] we3;
    reg                 [2:0] we_r;
    
//    assign we=we_r;
    assign we3 = (WE_EARLY > 0) ? (match_high & stb_d):we_r; // 3 bits wide - for each possible output
    assign we = we3[WE_WIDTH-1:0]; // truncate
235
    
236 237 238 239 240 241
    assign match_low=  {((ad ^ ADDR_LOW2)  & (8'hff & ADDR_MASK_LOW2)) == 0,
                        ((ad ^ ADDR_LOW1)  & (8'hff & ADDR_MASK_LOW1)) == 0,
                        ((ad ^ ADDR_LOW )  & (8'hff & ADDR_MASK_LOW )) == 0};
    assign match_high= {((ad ^ ADDR_HIGH2) & (8'hff & ADDR_MASK_HIGH2)) == 0,
                        ((ad ^ ADDR_HIGH1) & (8'hff & ADDR_MASK_HIGH1)) == 0,
                        ((ad ^ ADDR_HIGH ) & (8'hff & ADDR_MASK_HIGH )) == 0};
242 243
    
    always @ (posedge rst or posedge clk) begin
Andrey Filippov's avatar
Andrey Filippov committed
244 245 246
        if      (rst)  stb_d <= 3'b0;
        else if (srst) stb_d <= 3'b0;
        else           stb_d <= stb?match_low:3'b0;
247

Andrey Filippov's avatar
Andrey Filippov committed
248 249 250
        if      (rst)  we_r <= 3'b0;
        else if (srst) we_r <= 3'b0;
        else           we_r  <= match_high & stb_d;
251
        
252
        if      (rst)                                         deser_r[15:0]  <= 0;
Andrey Filippov's avatar
Andrey Filippov committed
253
        else if (srst)                                        deser_r[15:0]  <= 0;
254
        else if ((match_low && stb) || (match_high && stb_d)) deser_r[15:0] <= {ad,deser_r[15:8]};
255
    end
Andrey Filippov's avatar
Andrey Filippov committed
256
    assign data=0; // {DATA_WIDTH{1'b0}};
257 258
//    assign addr=deser_r[ADDR_WIDTH-1:0];
    assign addr=deser_r[8*WE_EARLY +: ADDR_WIDTH];
259 260 261 262 263 264 265
endmodule

module  cmd_deser_multi#(
    parameter ADDR=0,
    parameter ADDR_MASK='hffff,
    parameter NUM_CYCLES=6, // >=3
    parameter ADDR_WIDTH=16,
266 267 268 269 270
    parameter DATA_WIDTH=32,
    parameter ADDR1=0,
    parameter ADDR_MASK1=0,
    parameter ADDR2=0,
    parameter ADDR_MASK2=0,
271 272
    parameter WE_WIDTH=1,
    parameter WE_EARLY =    0    // if 1 - we and addr will be valid 1 cycle before data
273 274 275
)(
    input                   rst,
    input                   clk,
Andrey Filippov's avatar
Andrey Filippov committed
276
    input                   srst, // sync reset
277 278 279 280
    input             [7:0] ad,
    input                   stb,
    output [ADDR_WIDTH-1:0] addr,
    output [DATA_WIDTH-1:0] data,
281
    output   [WE_WIDTH-1:0] we
282 283 284 285 286
);
    localparam  ADDR_LOW= ADDR & 8'hff;
    localparam  ADDR_HIGH=(ADDR>>8) & 8'hff;
    localparam  ADDR_MASK_LOW= ADDR_MASK & 8'hff;
    localparam  ADDR_MASK_HIGH=(ADDR_MASK>>8) & 8'hff;
287 288 289 290 291 292 293 294 295 296 297 298

    localparam  ADDR_LOW1= ADDR1 & 8'hff;
    localparam  ADDR_MASK_LOW1= ADDR_MASK1 & 8'hff;
    localparam  ADDR_LOW2= ADDR2 & 8'hff;
    localparam  ADDR_MASK_LOW2= ADDR_MASK2 & 8'hff;

    localparam  ADDR_HIGH1=(ADDR1>>8) & 8'hff;
    localparam  ADDR_MASK_HIGH1=(ADDR_MASK1>>8) & 8'hff;
    localparam  ADDR_HIGH2=(ADDR2>>8) & 8'hff;
    localparam  ADDR_MASK_HIGH2=(ADDR_MASK2>>8) & 8'hff;

    
299
    reg    [8*NUM_CYCLES-1:0] deser_r;
300 301 302
    reg                 [2:0] stb_d;
    wire                [2:0] match_low;
    wire                [2:0] match_high;
303
    reg      [NUM_CYCLES-2:0] sr;
304 305
    reg      [NUM_CYCLES-2:0] sr1;
    reg      [NUM_CYCLES-2:0] sr2;
306 307 308 309 310 311
    wire                [2:0] we3;

    assign we3={sr2[WE_EARLY],sr1[WE_EARLY],sr[WE_EARLY]};
//    assign we=sr[WE_WIDTH-1:0]; // we_r;
    assign we=we3[WE_WIDTH-1:0]; // truncate to required number of bits
    
312 313 314 315 316 317
    assign match_low=  {((ad ^ ADDR_LOW2)  & (8'hff & ADDR_MASK_LOW2)) == 0,
                        ((ad ^ ADDR_LOW1)  & (8'hff & ADDR_MASK_LOW1)) == 0,
                        ((ad ^ ADDR_LOW )  & (8'hff & ADDR_MASK_LOW )) == 0};
    assign match_high= {((ad ^ ADDR_HIGH2) & (8'hff & ADDR_MASK_HIGH2)) == 0,
                        ((ad ^ ADDR_HIGH1) & (8'hff & ADDR_MASK_HIGH1)) == 0,
                        ((ad ^ ADDR_HIGH ) & (8'hff & ADDR_MASK_HIGH )) == 0};
318
    always @ (posedge rst or posedge clk) begin
Andrey Filippov's avatar
Andrey Filippov committed
319 320 321
        if       (rst) stb_d <= 0;
        else if (srst) stb_d <= 0;
        else           stb_d <= stb?match_low:3'b0;
322

323
        if      (rst)                       sr <= 0;
Andrey Filippov's avatar
Andrey Filippov committed
324
        else if (srst)                      sr <= 0;
325 326 327
        else if (match_high[0] && stb_d[0]) sr <= 1 << (NUM_CYCLES-2);
        else                                sr <= {1'b0,sr[NUM_CYCLES-2:1]};

Andrey Filippov's avatar
Andrey Filippov committed
328 329
        if      (rst)                       sr1 <= 0;
        else if (srst)                      sr1 <= 0;
330 331
        else if (match_high[1] && stb_d[1]) sr1 <= 1 << (NUM_CYCLES-2);
        else                                sr1 <= {1'b0,sr1[NUM_CYCLES-2:1]};
332

333
        if      (rst)                       sr2 <= 0;
Andrey Filippov's avatar
Andrey Filippov committed
334
        else if (srst)                      sr2 <= 0;
335 336
        else if (match_high[2] && stb_d[2]) sr2 <= 1 << (NUM_CYCLES-2);
        else                                sr2 <= {1'b0,sr2[NUM_CYCLES-2:1]};
337 338
        
        if      (rst)                       deser_r[8*NUM_CYCLES-1:0] <= 0;
Andrey Filippov's avatar
Andrey Filippov committed
339
        else if (srst)                      deser_r[8*NUM_CYCLES-1:0] <= 0;
340 341 342 343
        else if ((match_low &&  (|stb)) ||
                 (match_high && (|stb_d)) ||
                 (|sr) || (|sr1) || (|sr2)) deser_r[8*NUM_CYCLES-1:0] <= {ad,deser_r[8*NUM_CYCLES-1:8]};

344 345
    end
    assign data=deser_r[DATA_WIDTH+15:16];
346 347
//    assign addr=deser_r[ADDR_WIDTH-1:0];
    assign addr=deser_r[8*WE_EARLY +: ADDR_WIDTH];
348
endmodule