cmd_deser.v 12.4 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 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/> .
 *******************************************************************************/
`timescale 1ns/1ps

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

module  cmd_deser_dual#(
    parameter ADDR=0,
    parameter ADDR_MASK='hffff,
    parameter ADDR_WIDTH=12, // <=16
172 173 174 175 176
    parameter DATA_WIDTH=1,  // will 0 work?
    parameter ADDR1=0,
    parameter ADDR_MASK1=0,
    parameter ADDR2=0,
    parameter ADDR_MASK2=0,
177 178
    parameter WE_WIDTH=1,
    parameter WE_EARLY =    0    // if 1 - we and addr will be valid 1 cycle before data
179 180 181
)(
    input                   rst,
    input                   clk,
Andrey Filippov's avatar
Andrey Filippov committed
182
    input                   srst, // sync reset
183 184 185 186
    input             [7:0] ad,
    input                   stb,
    output [ADDR_WIDTH-1:0] addr,
    output [DATA_WIDTH-1:0] data,
187
    output   [WE_WIDTH-1:0] we
188 189 190 191 192
);
    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;
193 194 195 196 197 198 199 200 201 202 203 204

    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;


205
    reg                [15:0] deser_r;
206 207
//    reg                       stb_d;
    reg                 [2:0] stb_d;
208 209
    wire                [2:0] match_low;
    wire                [2:0] match_high;
210 211 212 213 214 215 216

    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
217
    
218 219 220 221 222 223
    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};
224 225
    
    always @ (posedge rst or posedge clk) begin
Andrey Filippov's avatar
Andrey Filippov committed
226 227 228
        if      (rst)  stb_d <= 3'b0;
        else if (srst) stb_d <= 3'b0;
        else           stb_d <= stb?match_low:3'b0;
229

Andrey Filippov's avatar
Andrey Filippov committed
230 231 232
        if      (rst)  we_r <= 3'b0;
        else if (srst) we_r <= 3'b0;
        else           we_r  <= match_high & stb_d;
233
        
234
        if      (rst)                                         deser_r[15:0]  <= 0;
Andrey Filippov's avatar
Andrey Filippov committed
235
        else if (srst)                                        deser_r[15:0]  <= 0;
236
        else if ((match_low && stb) || (match_high && stb_d)) deser_r[15:0] <= {ad,deser_r[15:8]};
237
    end
Andrey Filippov's avatar
Andrey Filippov committed
238
    assign data=0; // {DATA_WIDTH{1'b0}};
239 240
//    assign addr=deser_r[ADDR_WIDTH-1:0];
    assign addr=deser_r[8*WE_EARLY +: ADDR_WIDTH];
241 242 243 244 245 246 247
endmodule

module  cmd_deser_multi#(
    parameter ADDR=0,
    parameter ADDR_MASK='hffff,
    parameter NUM_CYCLES=6, // >=3
    parameter ADDR_WIDTH=16,
248 249 250 251 252
    parameter DATA_WIDTH=32,
    parameter ADDR1=0,
    parameter ADDR_MASK1=0,
    parameter ADDR2=0,
    parameter ADDR_MASK2=0,
253 254
    parameter WE_WIDTH=1,
    parameter WE_EARLY =    0    // if 1 - we and addr will be valid 1 cycle before data
255 256 257
)(
    input                   rst,
    input                   clk,
Andrey Filippov's avatar
Andrey Filippov committed
258
    input                   srst, // sync reset
259 260 261 262
    input             [7:0] ad,
    input                   stb,
    output [ADDR_WIDTH-1:0] addr,
    output [DATA_WIDTH-1:0] data,
263
    output   [WE_WIDTH-1:0] we
264 265 266 267 268
);
    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;
269 270 271 272 273 274 275 276 277 278 279 280

    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;

    
281
    reg    [8*NUM_CYCLES-1:0] deser_r;
282 283 284
    reg                 [2:0] stb_d;
    wire                [2:0] match_low;
    wire                [2:0] match_high;
285
    reg      [NUM_CYCLES-2:0] sr;
286 287
    reg      [NUM_CYCLES-2:0] sr1;
    reg      [NUM_CYCLES-2:0] sr2;
288 289 290 291 292 293
    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
    
294 295 296 297 298 299
    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};
300
    always @ (posedge rst or posedge clk) begin
Andrey Filippov's avatar
Andrey Filippov committed
301 302 303
        if       (rst) stb_d <= 0;
        else if (srst) stb_d <= 0;
        else           stb_d <= stb?match_low:3'b0;
304

305
        if      (rst)                       sr <= 0;
Andrey Filippov's avatar
Andrey Filippov committed
306
        else if (srst)                      sr <= 0;
307 308 309
        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
310 311
        if      (rst)                       sr1 <= 0;
        else if (srst)                      sr1 <= 0;
312 313
        else if (match_high[1] && stb_d[1]) sr1 <= 1 << (NUM_CYCLES-2);
        else                                sr1 <= {1'b0,sr1[NUM_CYCLES-2:1]};
314

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

326 327
    end
    assign data=deser_r[DATA_WIDTH+15:16];
328 329
//    assign addr=deser_r[ADDR_WIDTH-1:0];
    assign addr=deser_r[8*WE_EARLY +: ADDR_WIDTH];
330
endmodule