cmd_deser.v 13.3 KB
Newer Older
1 2 3
/*******************************************************************************
 * Module: cmd_deser
 * Date:2015-01-12  
4
 * Author: Andrey Filippov     
5 6
 * Description: Expand command address/data from a byte-wide
 *
7
 * Copyright (c) 2015 Elphel, Inc.
8 9 10 11 12 13 14 15 16 17 18 19
 * 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/> .
20 21 22 23 24 25
 *
 * 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"
26
 * files and/or simulating the code, the copyright holders of this Program give
27 28
 * 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
29
 * charge, and there is no dependence on any encrypted modules for simulating of
30 31 32
 * 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
 *******************************************************************************/
`timescale 1ns/1ps

module  cmd_deser#(
    parameter ADDR=0,
38 39 40 41 42 43 44 45 46
    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
47
)(
48 49
    input                                               rst,
    input                                               clk,
Andrey Filippov's avatar
Andrey Filippov committed
50
    input                                               srst, // sync reset
51 52 53 54 55
    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
56
);
57
    localparam  WE_WIDTH=(ADDR_MASK2!=0)?3:((ADDR_MASK1!=0)?2:1);
58 59 60
    generate
        if (NUM_CYCLES==1)
            cmd_deser_single # (
61 62 63 64 65 66 67 68
                .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),
69 70
                .WE_WIDTH   (WE_WIDTH),
                .WE_EARLY   (WE_EARLY)
71 72 73
            ) i_cmd_deser_single (
                .rst(rst),
                .clk(clk),
Andrey Filippov's avatar
Andrey Filippov committed
74
                .srst(srst),
75 76 77 78 79 80 81 82 83 84 85
                .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),
86 87 88 89 90
                .DATA_WIDTH(DATA_WIDTH),
                .ADDR1      (ADDR1),
                .ADDR_MASK1 (ADDR_MASK1),
                .ADDR2      (ADDR2),
                .ADDR_MASK2 (ADDR_MASK2),
91 92
                .WE_WIDTH   (WE_WIDTH),
                .WE_EARLY   (WE_EARLY)
Andrey Filippov's avatar
Andrey Filippov committed
93
            ) i_cmd_deser_dual (
94 95
                .rst(rst),
                .clk(clk),
Andrey Filippov's avatar
Andrey Filippov committed
96
                .srst(srst),
97 98 99 100 101 102 103 104 105 106 107 108
                .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),
109 110 111 112 113
                .DATA_WIDTH(DATA_WIDTH),
                .ADDR1      (ADDR1),
                .ADDR_MASK1 (ADDR_MASK1),
                .ADDR2      (ADDR2),
                .ADDR_MASK2 (ADDR_MASK2),
114 115
                .WE_WIDTH   (WE_WIDTH),
                .WE_EARLY   (WE_EARLY)
Andrey Filippov's avatar
Andrey Filippov committed
116
            ) i_cmd_deser_multi (
117 118
                .rst(rst),
                .clk(clk),
Andrey Filippov's avatar
Andrey Filippov committed
119
                .srst(srst),
120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
                .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
135 136 137 138 139
    parameter DATA_WIDTH=1,  // will 0 work?
    parameter ADDR1=0,
    parameter ADDR_MASK1=0,
    parameter ADDR2=0,
    parameter ADDR_MASK2=0,
140 141 142
    parameter WE_WIDTH=1,
    parameter WE_EARLY =    0 //
    
143 144 145
)(
    input                   rst,
    input                   clk,
Andrey Filippov's avatar
Andrey Filippov committed
146
    input                   srst, // sync reset
147 148 149 150
    input             [7:0] ad,
    input                   stb,
    output [ADDR_WIDTH-1:0] addr,
    output [DATA_WIDTH-1:0] data,
151
    output  [WE_WIDTH-1:0]  we
152 153 154
);
    localparam  ADDR_LOW= ADDR & 8'hff;
    localparam  ADDR_MASK_LOW= ADDR_MASK & 8'hff;
155 156 157 158
    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;
159
    reg                 [7:0] deser_r;
160
    wire                [2:0] match_low;
161
    reg         [2:0]         we_r;
162
    
163
    assign we = (WE_EARLY > 0)?(match_low[WE_WIDTH-1:0] & {WE_WIDTH{stb}}):we_r[WE_WIDTH-1:0];
164 165 166 167
    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};
168
    always @ (posedge rst or posedge clk) begin
Andrey Filippov's avatar
Andrey Filippov committed
169 170 171 172 173
        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; 
174
        else if ((|match_low) && stb) deser_r <= ad;
175 176
    end
    assign data={DATA_WIDTH{1'b0}};
177 178
//    assign addr=deser_r[ADDR_WIDTH-1:0];
    assign addr=(WE_EARLY>0) ? ad[ADDR_WIDTH-1:0]: deser_r[ADDR_WIDTH-1:0];
179 180 181 182 183 184
endmodule

module  cmd_deser_dual#(
    parameter ADDR=0,
    parameter ADDR_MASK='hffff,
    parameter ADDR_WIDTH=12, // <=16
185 186 187 188 189
    parameter DATA_WIDTH=1,  // will 0 work?
    parameter ADDR1=0,
    parameter ADDR_MASK1=0,
    parameter ADDR2=0,
    parameter ADDR_MASK2=0,
190 191
    parameter WE_WIDTH=1,
    parameter WE_EARLY =    0    // if 1 - we and addr will be valid 1 cycle before data
192 193 194
)(
    input                   rst,
    input                   clk,
Andrey Filippov's avatar
Andrey Filippov committed
195
    input                   srst, // sync reset
196 197 198 199
    input             [7:0] ad,
    input                   stb,
    output [ADDR_WIDTH-1:0] addr,
    output [DATA_WIDTH-1:0] data,
200
    output   [WE_WIDTH-1:0] we
201 202 203 204 205
);
    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;
206 207 208 209 210 211 212 213 214 215 216 217

    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;


218
    reg                [15:0] deser_r;
219 220
//    reg                       stb_d;
    reg                 [2:0] stb_d;
221 222
    wire                [2:0] match_low;
    wire                [2:0] match_high;
223 224 225 226 227 228 229

    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
230
    
231 232 233 234 235 236
    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};
237 238
    
    always @ (posedge rst or posedge clk) begin
Andrey Filippov's avatar
Andrey Filippov committed
239 240 241
        if      (rst)  stb_d <= 3'b0;
        else if (srst) stb_d <= 3'b0;
        else           stb_d <= stb?match_low:3'b0;
242

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

module  cmd_deser_multi#(
    parameter ADDR=0,
    parameter ADDR_MASK='hffff,
    parameter NUM_CYCLES=6, // >=3
    parameter ADDR_WIDTH=16,
261 262 263 264 265
    parameter DATA_WIDTH=32,
    parameter ADDR1=0,
    parameter ADDR_MASK1=0,
    parameter ADDR2=0,
    parameter ADDR_MASK2=0,
266 267
    parameter WE_WIDTH=1,
    parameter WE_EARLY =    0    // if 1 - we and addr will be valid 1 cycle before data
268 269 270
)(
    input                   rst,
    input                   clk,
Andrey Filippov's avatar
Andrey Filippov committed
271
    input                   srst, // sync reset
272 273 274 275
    input             [7:0] ad,
    input                   stb,
    output [ADDR_WIDTH-1:0] addr,
    output [DATA_WIDTH-1:0] data,
276
    output   [WE_WIDTH-1:0] we
277 278 279 280 281
);
    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;
282 283 284 285 286 287 288 289 290 291 292 293

    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;

    
294
    reg    [8*NUM_CYCLES-1:0] deser_r;
295 296 297
    reg                 [2:0] stb_d;
    wire                [2:0] match_low;
    wire                [2:0] match_high;
298
    reg      [NUM_CYCLES-2:0] sr;
299 300
    reg      [NUM_CYCLES-2:0] sr1;
    reg      [NUM_CYCLES-2:0] sr2;
301 302 303 304 305 306
    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
    
307 308 309 310 311 312
    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};
313
    always @ (posedge rst or posedge clk) begin
Andrey Filippov's avatar
Andrey Filippov committed
314 315 316
        if       (rst) stb_d <= 0;
        else if (srst) stb_d <= 0;
        else           stb_d <= stb?match_low:3'b0;
317

318
        if      (rst)                       sr <= 0;
Andrey Filippov's avatar
Andrey Filippov committed
319
        else if (srst)                      sr <= 0;
320 321 322
        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
323 324
        if      (rst)                       sr1 <= 0;
        else if (srst)                      sr1 <= 0;
325 326
        else if (match_high[1] && stb_d[1]) sr1 <= 1 << (NUM_CYCLES-2);
        else                                sr1 <= {1'b0,sr1[NUM_CYCLES-2:1]};
327

328
        if      (rst)                       sr2 <= 0;
Andrey Filippov's avatar
Andrey Filippov committed
329
        else if (srst)                      sr2 <= 0;
330 331
        else if (match_high[2] && stb_d[2]) sr2 <= 1 << (NUM_CYCLES-2);
        else                                sr2 <= {1'b0,sr2[NUM_CYCLES-2:1]};
332 333
        
        if      (rst)                       deser_r[8*NUM_CYCLES-1:0] <= 0;
Andrey Filippov's avatar
Andrey Filippov committed
334
        else if (srst)                      deser_r[8*NUM_CYCLES-1:0] <= 0;
335 336 337 338
        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]};

339 340
    end
    assign data=deser_r[DATA_WIDTH+15:16];
341 342
//    assign addr=deser_r[ADDR_WIDTH-1:0];
    assign addr=deser_r[8*WE_EARLY +: ADDR_WIDTH];
343
endmodule