sens_histogram.v 24.8 KB
Newer Older
1 2 3
/*******************************************************************************
 * Module: sens_histogram
 * Date:2015-05-29  
4
 * Author: Andrey Filippov     
5 6
 * Description: Calculates per-color histogram over the specified rectangular region
 *
7
 * Copyright (c) 2015 Elphel, Inc.
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
 * sens_histogram.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.
 *
 *  sens_histogram.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  sens_histogram #(
    parameter HISTOGRAM_RAM_MODE =     "NOBUF", // valid: "NOBUF" (32-bits, no buffering), "BUF18", "BUF32"
    parameter HISTOGRAM_ADDR =         'h33c,
26
    parameter HISTOGRAM_ADDR_MASK =    'h7fe,
27
    parameter HISTOGRAM_LEFT_TOP =     'h0,
28 29 30
    parameter HISTOGRAM_WIDTH_HEIGHT = 'h1, // 1.. 2^16, 0 - use HACT
    parameter [1:0] XOR_HIST_BAYER =  2'b00// 11 // invert bayer setting
    
31
)(
Andrey Filippov's avatar
Andrey Filippov committed
32 33 34
//    input         rst,
    input         mrst,      // @posedge mclk, sync reset
    input         prst,      // @posedge pclk, sync reset
35 36 37 38 39 40 41 42 43
    input         pclk,   // global clock input, pixel rate (96MHz for MT9P006)
    input         pclk2x,
    input         sof,
    input         hact,
    input   [7:0] hist_di, // 8-bit pixel data
    
    input         mclk,
    input         hist_en,  // @mclk - gracefully enable/disable histogram
    input         hist_rst, // @mclk - immediately disable if true
44 45
    output        hist_rq,
    input         hist_grant,
46 47 48
    output [31:0] hist_do,
    output        hist_dv,
    input   [7:0] cmd_ad,      // byte-serial command address/data (up to 6 bytes: AL-AH-D0-D1-D2-D3 
49 50
    input         cmd_stb,      // strobe (with first byte) for the command a/d
    input         monochrome    // tie to 0 to reduce hardware
51
);
52
    localparam PXD_2X_LATENCY = 2;
53 54
    reg         hist_bank_pclk;
    
55
//    reg   [7:0] hist_d;
56 57 58 59 60
    reg   [9:0] hist_addr;
    reg   [9:0] hist_addr_d;
    reg   [9:0] hist_addr_d2;
    reg   [9:0] hist_rwaddr;
    
61 62 63 64
    reg  [31:0] to_inc; // multiplexed, registered (either from memory or from previously incremented/saturated value)
//    wire [31:0] inc_w; // (before register)
    reg  [31:0] inc_r;  // incremented value, registered
    reg  [31:0] inc_sat; // inc_r registered and possibly saturated (in 18-bit mode), just registered in 32-bit mode) 
65 66
    wire [31:0] hist_new;
    reg         hist_rwen;  // read/write enable
67 68
//    reg   [2:0] hist_regen; // bram output register enable: [0] - ren, [1] - regen, [2] - next after regen
    reg   [1:0] hist_regen; // bram output register enable: [0] - ren, [1] - regen, [2] - next after regen
69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94
    reg         hist_we;    // bram write enable
    reg         hist_bank_mclk;
    
    wire          set_left_top_w;
    wire          set_width_height_w;
     
    wire    [1:0] pio_addr;
    wire   [31:0] pio_data;
    wire          pio_stb;
    
    reg    [31:0] lt_mclk;   // left+top @ posedge mclk
    reg    [31:0] wh_mclk;   // width+height @ posedge mclk
    reg    [15:0] width_m1;  // @posedge pclk
    reg    [15:0] height_m1; // @posedge pclk 
    reg    [15:0] left;      // @posedge pclk
    reg    [15:0] top;       // @posedge pclk
    
    reg           hist_en_pclk;  // @pclk - gracefully enable/disable histogram
    reg           hist_rst_pclk; // @pclk - immediately disable if true
    reg           en;
    reg           en_new; // @ pclk - enable new frame
    
    reg           en_mclk;
    
    wire          set_left_top_pclk;
    wire          set_width_height_pclk;
95
    reg           pclk_sync; // CE for pclk2x, ~=pclk
96 97
    
    reg     [1:0] bayer_pclk;
98 99
    
    reg     [1:0] hact_d;
100 101 102 103 104 105 106 107 108 109 110 111
    
    reg           top_margin;   // above (before) active window
    reg           hist_done;    // @pclk single cycle
    wire          hist_done_mclk;
    reg           vert_woi;     // vertically in window
    reg           left_margin;  // left of (before) active window
    reg    [2:0]  woi;          // @ pclk2x - inside WOI (and delayed
    reg           hor_woi;      // vertically in window
    reg    [15:0] vcntr;        // vertical (line) counter
    reg    [15:0] hcntr;        // horizontal (pixel) counter
    wire          vcntr_zero_w; // vertical counter is zero
    wire          hcntr_zero_w; // horizontal counter is zero
112 113
    reg           same_addr1; // @pclk2x - current histogram address is the same as previous (it was different color, but for future monochrome?)
    reg           same_addr2; // @pclk2x - current histogram address is the same as before-previous (previous was different color)
114 115 116 117 118 119
    

    reg           hist_out; // some data yet to be sent out
    reg           hist_out_d;
    reg     [2:0] hist_re;
    reg     [9:0] hist_raddr;
120
    reg           hist_rq_r;
121 122 123 124 125 126 127 128 129 130
    wire          hist_xfer_done_mclk; //@ mclk
    wire          hist_xfer_done; // @pclk
    reg           hist_xfer_busy; // @pclk, during histogram readout , immediately after woi (no gaps)
    reg           wait_readout;   // only used in NOBUF mode, in outher modes readout is expected to be always finished in time
    
    
    assign set_left_top_w =     pio_stb && (pio_addr == HISTOGRAM_LEFT_TOP );
    assign set_width_height_w = pio_stb && (pio_addr == HISTOGRAM_WIDTH_HEIGHT );
    assign vcntr_zero_w =      !(|vcntr);
    assign hcntr_zero_w =      !(|hcntr);
131
//    assign inc_w =             to_inc+1;
132

133
    assign hist_rq = hist_rq_r;
134
    assign hist_dv = hist_re[2];
135
    assign hist_xfer_done_mclk = hist_out_d && !hist_out && hist_en;
136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171

//AF2015-new mod
    wire       line_start_w = hact && !hact_d[0];
    reg        pre_first_line;
    reg        frame_active; // until done
    reg        hist_en_pclk2x;
//    reg        hist_rst_pclk2x;
    
    wire       hlstart;      // histogram line start @ posedge pclk2x
    reg  [7:0] pxd_ram [0:15] ; // crossing clock boundary
    reg  [1:0] bayer_ram [0:15] ; // crossing clock boundary
    reg  [0:0] woi_ram [0:15] ; // horizontal WOI to pclk2x
    reg  [3:0] pxd_wa;
    reg  [3:0] pxd_wa_woi;
    reg  [3:0] pxd_ra;
    reg  [3:0] pxd_ra_start; // start value of the pxd_ra counter to account for left margin
    
//    reg  [1:0] bayer_pclk;
    wire [1:0] bayer_2x = bayer_ram[pxd_ra];
    wire [7:0] pxd_2x   = pxd_ram[pxd_ra];
    wire       hor_woi_2x=woi_ram[pxd_ra];
    reg        monochrome_pclk;
    reg        monochrome_2x;
    
    always @ (posedge pclk) begin
        if (!hact) pxd_wa <= 0;
        else pxd_wa <= pxd_wa + 1;
        
        if (!hact) pxd_wa_woi <= -PXD_2X_LATENCY;
        else       pxd_wa_woi <= pxd_wa_woi + 1;
        
        if (hist_en_pclk && hact)      pxd_ram[pxd_wa] <= hist_di;
        if (hist_en_pclk && hact)      bayer_ram[pxd_wa] <= bayer_pclk;
        if (hist_en_pclk && hact_d[1]) woi_ram[pxd_wa_woi] <= hor_woi;          // PXD_2X_LATENCY;
        
    end
172 173 174 175 176 177 178 179 180 181 182 183
    
    
    always @ (posedge mclk) begin
        if (set_left_top_w)     lt_mclk <= pio_data;
        if (set_width_height_w) wh_mclk <= pio_data;
    end
    
    always @ (posedge pclk) begin
        if (set_left_top_pclk)     {top,left} <= lt_mclk[31:0];
        if (set_width_height_pclk) {height_m1,width_m1} <= wh_mclk[31:0];
    end
    
184 185
    // process WOI
//    wire  eol = !hact && hact_d[0];
186
    always @ (posedge pclk) begin
187 188 189 190 191 192 193 194
        hact_d <= {hact_d[0],hact};
        if      (!en)           pre_first_line <= 0;
        else if (sof && en_new) pre_first_line <= 1;
        else if (hact)          pre_first_line <= 0;
    
        if      (!en)                         top_margin <= 0;
        else if (sof && en_new)               top_margin <= 1;
        else if (vcntr_zero_w & line_start_w) top_margin <= 0;
195
        
196 197
        if (!en ||(pre_first_line && !hact))  vert_woi <= 0;
        else if (vcntr_zero_w & line_start_w) vert_woi <= top_margin;
198
        
199
        hist_done <= vcntr_zero_w && vert_woi && line_start_w;
200
        
201 202
        if   (!en || hist_done)               frame_active <= 0;
        else if (sof && en_new)               frame_active <= 1;
203 204
        
        
205 206
        if ((pre_first_line && !hact) || !frame_active) vcntr <= top;
        else if (line_start_w)                          vcntr <= vcntr_zero_w ? height_m1 : (vcntr - 1);
207
        
208 209 210
        if (!frame_active)                    left_margin <= 0;
        else if (!hact_d[0])                  left_margin <= 1;
        else if (hcntr_zero_w)                left_margin <= 0;
211

212 213 214
        // !hact_d[0] to limit by right margin if window is set wrong
        if (!vert_woi || wait_readout || !hact_d[0]) hor_woi <= 0; // postpone WOI if reading out/erasing histogram (no-buffer mode)
        else if (hcntr_zero_w)                       hor_woi <= left_margin && vert_woi;
215
        
216
        if      (!hact_d[0])                  hcntr <= left;
217 218 219
        else if (hcntr_zero_w && left_margin) hcntr <= width_m1;
        else if (left_margin || hor_woi)      hcntr <= hcntr - 1;
        
220
//        if (hor_woi) hist_d <= hist_di;
221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236
        
        if      (!en)                                          hist_bank_pclk <= 0;
        else if (hist_done && (HISTOGRAM_RAM_MODE != "NOBUF")) hist_bank_pclk <= !hist_bank_pclk;
        // hist_xfer_busy to extend en
        if      (!en)                      hist_xfer_busy <= 0;
        else if (hist_xfer_done)           hist_xfer_busy <= 0;
        else if (vcntr_zero_w && vert_woi) hist_xfer_busy <= 1;
        
        hist_en_pclk <= hist_en;
        hist_rst_pclk <= hist_rst;
        
        if      (hist_rst_pclk)                               en <= 0;
        else if (hist_en_pclk)                                en <= 1;
        else if (!top_margin && !vert_woi && !hist_xfer_busy) en <= 0;
        
        en_new <= !hist_rst_pclk && hist_en_pclk;
237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259

        if      (monochrome_pclk)         bayer_pclk[1] <= 0;
        else if (!hact && hact_d[0])      bayer_pclk[1] <= !bayer_pclk[1];
        else if (pre_first_line && !hact) bayer_pclk[1] <= XOR_HIST_BAYER[1];

        if      (monochrome_pclk)         bayer_pclk[0] <= 0;
        else if (!hact)                   bayer_pclk[0] <= XOR_HIST_BAYER[0];
        else                              bayer_pclk[0] <= ~bayer_pclk[0]; 

//line_start_w        
    end

    always @(posedge pclk2x) begin
        monochrome_2x <= monochrome;
        hist_en_pclk2x <= hist_en;
//        hist_rst_pclk2x <= hist_rst;
        pxd_ra_start <= left[3:0];
        
        if (!hist_en_pclk2x || hlstart || !(hor_woi_2x || (|woi)))  pclk_sync <= 0;
        else                                                        pclk_sync <= ~pclk_sync;
        
        if (hlstart)        pxd_ra <= pxd_ra_start;
        else if (pclk_sync) pxd_ra <= pxd_ra + 1;
260 261
        
    end
262
    
263 264 265 266


    always @(posedge pclk2x) begin
        if (pclk_sync)  begin
267 268
            woi <= {woi[1:0],hor_woi_2x};
            hist_addr <= {bayer_2x,pxd_2x};
269 270
            hist_addr_d <= hist_addr;
            hist_addr_d2 <= hist_addr_d;
271 272 273 274 275 276 277
            same_addr1 <= monochrome_2x && woi[0] && woi[1] && (hist_addr_d  == hist_addr); // reduce hardware if hard-wire to gnd
            same_addr2 <=                  woi[0] && woi[2] && (hist_addr_d2 == hist_addr);
//            if (same_addr) to_inc <= inc_r;
//            else           to_inc <= hist_new;
            if      (same_addr1) to_inc <= inc_r; // only used in monochrome mode
            else if (same_addr2) to_inc <= inc_sat;
            else                 to_inc <= hist_new;
278
            
279 280 281
            if      (HISTOGRAM_RAM_MODE != "BUF18")  inc_sat <= inc_r;
            else if (inc_r[18])                      inc_sat <= 32'h3fff; // maximal value
            else                                     inc_sat <= {14'b0,inc_r[17:0]};
282 283
        end
        hist_rwen <= (woi[0] & ~pclk_sync) || (woi[2] & pclk_sync);
284 285
//        hist_regen <= {hist_regen[1:0], woi[0] & ~pclk_sync};
        hist_regen <= {hist_regen[0], woi[0] & ~pclk_sync};
286 287 288 289
        hist_we <= woi[2] & pclk_sync;
        
        if     (woi[0] & ~pclk_sync) hist_rwaddr <= hist_addr;
        else if (woi[2] & pclk_sync) hist_rwaddr <= hist_addr_d2;
290 291
        
        inc_r <= to_inc + 1;
292

293 294 295
//        if      (HISTOGRAM_RAM_MODE != "BUF18")  inc_r <= inc_w;
//        else if (inc_w[18])                      inc_r <= 32'h3fff; // maximal value
//        else                                     inc_r <= {14'b0,inc_w[17:0]};
296 297
        
    end
298 299
    // after hist_out was off, require inactive grant before sending rq
    reg en_rq_start;
300 301 302
    
    always @ (posedge mclk) begin
        en_mclk <= en;
303
        monochrome_pclk <= monochrome;
304 305 306 307 308
        if      (!en_mclk)       hist_out <= 0;
        else if (hist_done_mclk) hist_out <= 1;
        else if (&hist_raddr)    hist_out <= 0;
        
        hist_out_d <= hist_out;
309 310 311 312
        // reset address each time new transfer is started
//        if      (!en_mclk || (hist_out && !hist_out_d)) hist_raddr <= 0;
        if      (!hist_out)  hist_raddr <= 0;
        else if (hist_re[0]) hist_raddr <= hist_raddr + 1;
313
        
314 315 316
//        if      (!en_mclk)             hist_rq_r <= 0;
//        else if (hist_out && !hist_re) hist_rq_r <= 1;

317 318 319 320 321 322
//        hist_rq_r <= en_mclk && hist_out && !(&hist_raddr);
// prevent starting rq if grant is still on (back-to-back)
        if      (!hist_out)   en_rq_start <= 0;
        else if (!hist_grant) en_rq_start <= 1;
//        hist_rq_r <= en_mclk && hist_out && !(&hist_raddr) && ((|hist_raddr[9:0]) || !hist_grant);
        hist_rq_r <= en_mclk && hist_out && !(&hist_raddr) && en_rq_start;
323
        
324 325
        if      (!hist_out || (&hist_raddr[7:0])) hist_re[0] <= 0;
        else if (hist_grant && hist_out)          hist_re[0] <= 1;
326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351
        
        hist_re[2:1] <= hist_re[1:0];
        
        if      (!en_mclk)                                               hist_bank_mclk <= 0;
        else if (hist_xfer_done_mclk && (HISTOGRAM_RAM_MODE != "NOBUF")) hist_bank_mclk <= !hist_bank_mclk;
    
    end
    
    always @ (posedge pclk) begin
        if      (!en)                                          wait_readout <= 0;
        else if ((HISTOGRAM_RAM_MODE == "NOBUF") && hist_done) wait_readout <= 1;
        else if (hist_xfer_done)                               wait_readout <= 0;
    
    end

    
    cmd_deser #(
        .ADDR        (HISTOGRAM_ADDR),
        .ADDR_MASK   (HISTOGRAM_ADDR_MASK),
        .NUM_CYCLES  (6),
        .ADDR_WIDTH  (2),
        .DATA_WIDTH  (32),
        .ADDR1       (0),
        .ADDR_MASK1  (0),
        .ADDR2       (0),
        .ADDR_MASK2  (0)
352
    ) cmd_deser_sens_histogram_i (
Andrey Filippov's avatar
Andrey Filippov committed
353
        .rst         (1'b0), // input
354
        .clk         (mclk), // input
Andrey Filippov's avatar
Andrey Filippov committed
355
        .srst        (mrst), // input
356 357 358 359 360 361
        .ad          (cmd_ad), // input[7:0] 
        .stb         (cmd_stb), // input
        .addr        (pio_addr), // output[15:0] 
        .data        (pio_data), // output[31:0] 
        .we          (pio_stb) // output
    );
362 363 364 365 366 367 368 369 370 371 372

    pulse_cross_clock pulse_cross_clock_hlstart_start_i (
        .rst         (prst), // input
        .src_clk     (pclk), // input
        .dst_clk     (pclk2x), // input
        .in_pulse    (hcntr_zero_w && left_margin && hact_d[0]), // input
        .out_pulse   (hlstart),    // output
        .busy() // output
    );


373 374
    
    pulse_cross_clock pulse_cross_clock_lt_i (
Andrey Filippov's avatar
Andrey Filippov committed
375
        .rst         (mrst), // input
376 377 378 379 380 381 382 383
        .src_clk     (mclk), // input
        .dst_clk     (pclk), // input
        .in_pulse    (set_left_top_w), // input
        .out_pulse   (set_left_top_pclk),    // output
        .busy() // output
    );
    
    pulse_cross_clock pulse_cross_clock_wh_i (
Andrey Filippov's avatar
Andrey Filippov committed
384
        .rst         (mrst), // input
385 386 387 388 389 390 391 392
        .src_clk     (mclk), // input
        .dst_clk     (pclk), // input
        .in_pulse    (set_width_height_w), // input
        .out_pulse   (set_width_height_pclk),    // output
        .busy() // output
    );
    
    pulse_cross_clock pulse_cross_clock_hist_done_i (
Andrey Filippov's avatar
Andrey Filippov committed
393
        .rst         (prst), // input
394 395 396 397 398 399 400 401
        .src_clk     (pclk), // input
        .dst_clk     (mclk), // input
        .in_pulse    (hist_done), // input
        .out_pulse   (hist_done_mclk),    // output
        .busy() // output
    );

    pulse_cross_clock pulse_cross_clock_hist_xfer_done_i (
Andrey Filippov's avatar
Andrey Filippov committed
402
        .rst         (mrst), // input
403 404 405 406 407 408
        .src_clk     (mclk), // input
        .dst_clk     (pclk), // input
        .in_pulse    (hist_xfer_done_mclk), // input
        .out_pulse   (hist_xfer_done),    // output
        .busy() // output
    );
409
/*   
410 411 412 413 414
    clk_to_clk2x clk_to_clk2x_i (
        .clk         (pclk), // input
        .clk2x       (pclk2x), // input
        .clk_sync    (pclk_sync) // output
    );
415
*/    
416 417 418 419 420 421 422 423
    //TODO:  make it double cycle in timing

    // select between 18-bit wide histogram data using a single BRAM or 2 BRAMs having full 32 bits    
    generate
        if (HISTOGRAM_RAM_MODE=="BUF18")
            sens_hist_ram_double sens_hist_ram_i (
                .pclk2x     (pclk2x), // input
                .addr_a     ({hist_bank_pclk,hist_rwaddr[9:0]}), // input[10:0] 
424
                .data_in_a  (inc_sat),         // input[31:0] 
425 426 427 428 429 430 431 432 433 434 435 436 437 438
                .data_out_a (hist_new),      // output[31:0] 
                .en_a       (hist_rwen),     // input
                .regen_a    (hist_regen[1]), // input
                .we_a       (hist_we),       // input
                .mclk       (mclk),          // input
                .addr_b     ({hist_bank_mclk,hist_raddr[9:0]}), // input[10:0] 
                .data_out_b (hist_do),       // output[31:0] 
                .re_b       (hist_re[0]),    // input
                .regen_b    (hist_re[1])     // input
            );
        else if (HISTOGRAM_RAM_MODE=="BUF32")
            sens_hist_ram_single sens_hist_ram_i (
                .pclk2x     (pclk2x), // input
                .addr_a     ({hist_bank_pclk,hist_rwaddr[9:0]}), // input[10:0] 
439
                .data_in_a  (inc_sat),      // input[31:0] 
440 441 442 443 444 445 446 447 448 449 450 451 452 453
                .data_out_a (hist_new),   // output[31:0] 
                .en_a       (hist_rwen),  // input
                .regen_a    (hist_regen[1]), // input
                .we_a       (hist_we),    // input
                .mclk       (mclk),       // input
                .addr_b     ({hist_bank_mclk,hist_raddr[9:0]}), // input[10:0] 
                .data_out_b (hist_do), // output[31:0] 
                .re_b       (hist_re[0]),    // input
                .regen_b    (hist_re[1])     // input
            );
        else if (HISTOGRAM_RAM_MODE=="NOBUF")
            sens_hist_ram_nobuff sens_hist_ram_i (
                .pclk2x     (pclk2x), // input
                .addr_a     ({hist_bank_pclk,hist_rwaddr[9:0]}), // input[10:0] 
454
                .data_in_a  (inc_sat),      // input[31:0] 
455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 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 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622
                .data_out_a (hist_new),   // output[31:0] 
                .en_a       (hist_rwen),  // input
                .regen_a    (hist_regen[1]), // input
                .we_a       (hist_we),    // input
                .mclk       (mclk),       // input
                .addr_b     ({hist_bank_mclk,hist_raddr[9:0]}), // input[10:0] 
                .data_out_b (hist_do), // output[31:0] 
                .re_b       (hist_re[0]),    // input
                .regen_b    (hist_re[1])     // input
            );
        
    endgenerate


endmodule

module sens_hist_ram_single(
    input         pclk2x,
    input  [10:0] addr_a,
    input  [31:0] data_in_a,
    output [31:0] data_out_a,
    input         en_a,
    input         regen_a,
    input         we_a,
    
    input         mclk,
    input  [10:0] addr_b,
    output [31:0] data_out_b,
    input         re_b,
    input         regen_b
);
    wire   [17:0] data_out_a18;
    wire   [17:0] data_out_b18;
    assign data_out_b = {14'b0,data_out_b18};
    assign data_out_a = {14'b0,data_out_a18};
    ramtp_var_w_var_r #(
        .REGISTERS_A(1),
        .REGISTERS_B(1),
        .LOG2WIDTH_A(4),               // 18 bits
        .LOG2WIDTH_B(4),                // 18 bits
        .WRITE_MODE_A("NO_CHANGE"),
        .WRITE_MODE_B("READ_FIRST")
    ) ramtp_var_w_var_r_i (
        .clk_a      (pclk2x),          // input
        .addr_a     (addr_a),          // input[10:0] 
        .en_a       (en_a),            // input
        .regen_a    (regen_a),         // input
        .we_a       (we_a),            // input
        .data_out_a (data_out_a18),    // output[17:0] 
        .data_in_a  (data_in_a[17:0]), // input[17:0] 
        .clk_b      (mclk),            // input
        .addr_b     (addr_b),          // input[10:0] 
        .en_b       (re_b),            // input
        .regen_b    (regen_b),         // input
        .we_b       (1'b1),            // input
        .data_out_b (data_out_b18),    // output[17:0] 
        .data_in_b  (18'b0)            // input[17:0] 
    );
endmodule
// TODO: without ping-pong buffering as histograms are transferred to the system memory over axi master,
// it may be possible to use a single RAM block (if vertical blanking outside of selected window is sufficient)

module sens_hist_ram_double(
    input         pclk2x,
    input  [10:0] addr_a,
    input  [31:0] data_in_a,
    output [31:0] data_out_a,
    input         en_a,
    input         regen_a,
    input         we_a,
    
    input         mclk,
    input  [10:0] addr_b,
    output [31:0] data_out_b,
    input         re_b,
    input         regen_b
);
    
    ramt_var_w_var_r #(
        .REGISTERS_A(1),
        .REGISTERS_B(1),
        .LOG2WIDTH_A(4),
        .LOG2WIDTH_B(4),
        .WRITE_MODE_A("NO_CHANGE"),
        .WRITE_MODE_B("READ_FIRST")
    ) ramt_var_w_var_r_lo_i (
        .clk_a      (pclk2x),           // input
        .addr_a     (addr_a),           // input[10:0] 
        .en_a       (en_a),             // input
        .regen_a    (regen_a),          // input
        .we_a       (we_a),             // input
        .data_out_a (data_out_a[15:0]), // output[15:0] 
        .data_in_a  (data_in_a[15:0]),  // input[15:0] 
        .clk_b      (mclk),             // input
        .addr_b     (addr_b),           // input[10:0] 
        .en_b       (re_b),             // input
        .regen_b    (regen_b),          // input
        .we_b       (1'b1),             // input
        .data_out_b (data_out_b[15:0]), // output[15:0] 
        .data_in_b  (16'b0)             // input[15:0] 
    );
    
    ramt_var_w_var_r #(
        .REGISTERS_A(1),
        .REGISTERS_B(1),
        .LOG2WIDTH_A(4),
        .LOG2WIDTH_B(4),
        .WRITE_MODE_A("NO_CHANGE"),
        .WRITE_MODE_B("READ_FIRST")
    ) ramt_var_w_var_r_hi_i (
        .clk_a      (pclk2x),           // input
        .addr_a     (addr_a),           // input[10:0] 
        .en_a       (en_a),             // input
        .regen_a    (regen_a),          // input
        .we_a       (we_a),             // input
        .data_out_a (data_out_a[31:16]),// output[15:0] 
        .data_in_a  (data_in_a[31:16]), // input[15:0] 
        .clk_b      (mclk),             // input
        .addr_b     (addr_b),           // input[10:0] 
        .en_b       (re_b),             // input
        .regen_b    (regen_b),          // input
        .we_b       (1'b1),             // input
        .data_out_b (data_out_b[31:16]),// output[15:0] 
        .data_in_b  (16'b0)             // input[15:0] 
    );
endmodule

module sens_hist_ram_nobuff(
    input         pclk2x,
    input  [10:0] addr_a,
    input  [31:0] data_in_a,
    output [31:0] data_out_a,
    input         en_a,
    input         regen_a,
    input         we_a,
    
    input         mclk,
    input  [10:0] addr_b,
    output [31:0] data_out_b,
    input         re_b,
    input         regen_b
);
    
    ramt_var_w_var_r #(
        .REGISTERS_A(1),
        .REGISTERS_B(1),
        .LOG2WIDTH_A(5), // 32 bits
        .LOG2WIDTH_B(5),
        .WRITE_MODE_A("NO_CHANGE"),
        .WRITE_MODE_B("READ_FIRST")
    ) ramt_var_w_var_r_i (
        .clk_a      (pclk2x),           // input
        .addr_a     (addr_a[9:0]),      // input[10:0] 
        .en_a       (en_a),             // input
        .regen_a    (regen_a),          // input
        .we_a       (we_a),             // input
        .data_out_a (data_out_a[31:0]), // output[15:0] 
        .data_in_a  (data_in_a[31:0]),  // input[15:0] 
        .clk_b      (mclk),             // input
        .addr_b     (addr_b[9:0]),      // input[10:0] 
        .en_b       (re_b),             // input
        .regen_b    (regen_b),          // input
        .we_b       (1'b1),             // input
        .data_out_b (data_out_b[31:0]), // output[15:0] 
        .data_in_b  (32'b0)             // input[15:0] 
    );
    
endmodule
623 624 625 626 627 628 629 630 631 632 633

module  sens_histogram_dummy(
    output        hist_rq,
    output [31:0] hist_do,
    output        hist_dv

);
    assign         hist_rq = 0;
    assign         hist_do = 0;
    assign         hist_dv = 0;
endmodule