sens_histogram.v 26.5 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11
/*!
 * <b>Module:</b>sens_histogram
 * @file sens_histogram.v
 * @date 2015-05-29  
 * @author Andrey Filippov     
 *
 * @brief Calculates per-color histogram over the specified rectangular region
 *
 * @copyright Copyright (c) 2015 Elphel, Inc.
 *
 * <b>License:</b>
12 13 14 15 16 17 18 19 20 21 22 23 24
 *
 * 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/> .
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
`timescale 1ns/1ps
40 41 42
    // TODO: get rid of pclk2x by doubling memories (making 1 write port and 2 read ones)
    // How to erase?
    // Alternative: copy/erase to a separate buffer in the beginning/end of a frame?
43 44

module  sens_histogram #(
45
    parameter HISTOGRAM_RAM_MODE =     "BUF32", // "NOBUF", // valid: "NOBUF" (32-bits, no buffering), "BUF18", "BUF32"
46
    parameter HISTOGRAM_ADDR =         'h33c,
47
    parameter HISTOGRAM_ADDR_MASK =    'h7fe,
48
    parameter HISTOGRAM_LEFT_TOP =     'h0,
49 50
    parameter HISTOGRAM_WIDTH_HEIGHT = 'h1, // 1.. 2^16, 0 - use HACT
    parameter [1:0] XOR_HIST_BAYER =  2'b00// 11 // invert bayer setting
51 52 53
`ifdef DEBUG_RING
        ,parameter DEBUG_CMD_LATENCY = 2 // SuppressThisWarning VEditor - not used
`endif        
54
    
55
)(
Andrey Filippov's avatar
Andrey Filippov committed
56 57
    input         mrst,      // @posedge mclk, sync reset
    input         prst,      // @posedge pclk, sync reset
58 59 60
    input         pclk,   // global clock input, pixel rate (96MHz for MT9P006)
    input         pclk2x,
    input         sof,
61
    input         eof,
62 63
    input         hact,
    input   [7:0] hist_di, // 8-bit pixel data
64
    input   [1:0] bayer,
65 66 67
    input         mclk,
    input         hist_en,  // @mclk - gracefully enable/disable histogram
    input         hist_rst, // @mclk - immediately disable if true
68 69
    output        hist_rq,
    input         hist_grant,
70 71 72
    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 
73 74
    input         cmd_stb,      // strobe (with first byte) for the command a/d
    input         monochrome    // tie to 0 to reduce hardware
75 76 77 78 79
`ifdef DEBUG_RING       
    ,output                       debug_do, // output to the debug ring
     input                        debug_sl, // 0 - idle, (1,0) - shift, (1,1) - load // SuppressThisWarning VEditor - not used
     input                        debug_di  // input from the debug ring
`endif         
80
);
81

82
    localparam PXD_2X_LATENCY = 2;
83 84
    reg         hist_bank_pclk;
    
85
//    reg   [7:0] hist_d;
86 87 88 89 90
    reg   [9:0] hist_addr;
    reg   [9:0] hist_addr_d;
    reg   [9:0] hist_addr_d2;
    reg   [9:0] hist_rwaddr;
    
91 92 93 94
    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) 
95 96
    wire [31:0] hist_new;
    reg         hist_rwen;  // read/write enable
97 98
//    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
99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124
    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;
125
    reg           pclk_sync; // CE for pclk2x, ~=pclk
126 127
    
    reg     [1:0] bayer_pclk;
128 129
    
    reg     [1:0] hact_d;
130 131 132 133
    
    reg           top_margin;   // above (before) active window
    reg           hist_done;    // @pclk single cycle
    wire          hist_done_mclk;
134
    reg           vert_woi;     // vertically in window TESTED ACTIVE
135 136 137 138 139 140 141
    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
142 143
    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)
144 145 146 147 148 149
    

    reg           hist_out; // some data yet to be sent out
    reg           hist_out_d;
    reg     [2:0] hist_re;
    reg     [9:0] hist_raddr;
150
    reg           hist_rq_r;
151 152 153 154 155
    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
    
156
`ifdef DEBUG_RING
157 158
    reg    [15:0] debug_line_cntr;
    reg    [15:0] debug_lines;
159
`endif    
160 161 162 163 164
    
    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);
165
//    assign inc_w =             to_inc+1;
166

167
    assign hist_rq = hist_rq_r;
168
    assign hist_dv = hist_re[2];
169
    assign hist_xfer_done_mclk = hist_out_d && !hist_out && hist_en;
170 171

//AF2015-new mod
172
    wire       line_start_w = hact && !hact_d[0]; // // tested active
173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193
    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;
    
194
`ifdef DEBUG_RING
195 196 197 198 199 200
    always @ (posedge pclk) begin
        if      (sof)          debug_line_cntr <= 0;
        else if (line_start_w) debug_line_cntr <= debug_line_cntr + 1;
        
        if      (sof)          debug_lines <= debug_line_cntr;
    end
201
`endif    
202
    
203 204 205 206 207 208 209 210 211 212 213 214
    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
215 216 217 218 219 220 221 222 223 224 225 226
    
    
    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
    
227
    // process WOI
228
    always @ (posedge pclk) begin
229 230 231 232 233 234 235 236
        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;
237
        
238 239
        if (!en ||(pre_first_line && !hact))  vert_woi <= 0;
        else if (vcntr_zero_w & line_start_w) vert_woi <= top_margin;
240
        
241
        hist_done <= vert_woi && (eof || (vcntr_zero_w && line_start_w)); // hist done never asserted, line_start_w - active
242
        
243 244
        if   (!en || hist_done)               frame_active <= 0;
        else if (sof && en_new)               frame_active <= 1;
245 246
        
        
247 248
        if ((pre_first_line && !hact) || !frame_active) vcntr <= top;
        else if (line_start_w)                          vcntr <= vcntr_zero_w ? height_m1 : (vcntr - 1);
249
        
250 251 252
        if (!frame_active)                    left_margin <= 0;
        else if (!hact_d[0])                  left_margin <= 1;
        else if (hcntr_zero_w)                left_margin <= 0;
253

254 255 256
        // !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;
257
        
258
        if      (!hact_d[0])                  hcntr <= left;
259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276
        else if (hcntr_zero_w && left_margin) hcntr <= width_m1;
        else if (left_margin || hor_woi)      hcntr <= hcntr - 1;
        
        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;
277 278 279

        if      (monochrome_pclk)         bayer_pclk[1] <= 0;
        else if (!hact && hact_d[0])      bayer_pclk[1] <= !bayer_pclk[1];
280
        else if (pre_first_line && !hact) bayer_pclk[1] <= XOR_HIST_BAYER[1] ^ bayer[1];
281 282

        if      (monochrome_pclk)         bayer_pclk[0] <= 0;
283
        else if (!hact)                   bayer_pclk[0] <= XOR_HIST_BAYER[0] ^ bayer[0];
284 285 286 287 288 289 290 291 292 293 294 295 296 297
        else                              bayer_pclk[0] <= ~bayer_pclk[0]; 

    end

    always @(posedge pclk2x) begin
        monochrome_2x <= monochrome;
        hist_en_pclk2x <= hist_en;
        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;
298 299
        
    end
300
    
301 302 303 304


    always @(posedge pclk2x) begin
        if (pclk_sync)  begin
305 306
            woi <= {woi[1:0],hor_woi_2x};
            hist_addr <= {bayer_2x,pxd_2x};
307 308
            hist_addr_d <= hist_addr;
            hist_addr_d2 <= hist_addr_d;
309 310 311 312 313
            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_addr1) to_inc <= inc_r; // only used in monochrome mode
            else if (same_addr2) to_inc <= inc_sat;
            else                 to_inc <= hist_new;
314
            
315 316 317
            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]};
318 319
        end
        hist_rwen <= (woi[0] & ~pclk_sync) || (woi[2] & pclk_sync);
320
        hist_regen <= {hist_regen[0], woi[0] & ~pclk_sync};
321 322 323 324
        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;
325 326
        
        inc_r <= to_inc + 1;
327 328
        
    end
329 330
    // after hist_out was off, require inactive grant before sending rq
    reg en_rq_start;
331 332 333
    
    always @ (posedge mclk) begin
        en_mclk <= en;
334
//        monochrome_pclk <= monochrome;
335 336 337 338 339
        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;
340 341 342
        // reset address each time new transfer is started
        if      (!hist_out)  hist_raddr <= 0;
        else if (hist_re[0]) hist_raddr <= hist_raddr + 1;
343
        
344 345 346 347
// 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) && en_rq_start;
348
        
349 350
        if      (!hist_out || (&hist_raddr[7:0])) hist_re[0] <= 0;
        else if (hist_grant && hist_out)          hist_re[0] <= 1;
351 352 353 354 355 356 357 358 359 360 361 362 363
        
        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;
    
364
        monochrome_pclk <= monochrome;
365 366
    end

367 368 369 370 371 372 373 374 375 376 377 378
`ifdef DEBUG_RING
    debug_slave #(
        .SHIFT_WIDTH       (64),
        .READ_WIDTH        (64),
        .WRITE_WIDTH       (32),
        .DEBUG_CMD_LATENCY (DEBUG_CMD_LATENCY)
    ) debug_slave_i (
        .mclk       (mclk),     // input
        .mrst       (mrst),     // input
        .debug_di   (debug_di), // input
        .debug_sl   (debug_sl), // input
        .debug_do   (debug_do), // output
379
        .rd_data   ({debug_lines[15:0], debug_line_cntr[15:0], width_m1[15:0],  hcntr[15:0]}), // input[31:0] 
380 381 382 383
        .wr_data    (), // output[31:0]  - not used
        .stb        () // output  - not used
    );
`endif
384 385 386 387 388 389 390 391 392 393 394
    
    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)
395
    ) cmd_deser_sens_histogram_i (
Andrey Filippov's avatar
Andrey Filippov committed
396
        .rst         (1'b0), // input
397
        .clk         (mclk), // input
Andrey Filippov's avatar
Andrey Filippov committed
398
        .srst        (mrst), // input
399 400 401 402 403 404
        .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
    );
405 406 407 408 409 410 411 412 413 414 415

    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
    );


416 417
    
    pulse_cross_clock pulse_cross_clock_lt_i (
Andrey Filippov's avatar
Andrey Filippov committed
418
        .rst         (mrst), // input
419 420 421 422 423 424 425 426
        .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
427
        .rst         (mrst), // input
428 429 430 431 432 433 434 435
        .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
436
        .rst         (prst), // input
437 438 439 440 441 442 443 444
        .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
445
        .rst         (mrst), // input
446 447 448 449 450 451 452 453 454 455
        .src_clk     (mclk), // input
        .dst_clk     (pclk), // input
        .in_pulse    (hist_xfer_done_mclk), // input
        .out_pulse   (hist_xfer_done),    // output
        .busy() // output
    );
    //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
456
        if (HISTOGRAM_RAM_MODE=="BUF32")
457 458 459
            sens_hist_ram_double sens_hist_ram_i (
                .pclk2x     (pclk2x), // input
                .addr_a     ({hist_bank_pclk,hist_rwaddr[9:0]}), // input[10:0] 
460
                .data_in_a  (inc_sat),         // input[31:0] 
461 462 463 464 465 466 467 468 469 470
                .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
            );
471
        else if (HISTOGRAM_RAM_MODE=="BUF18")
472 473 474
            sens_hist_ram_single sens_hist_ram_i (
                .pclk2x     (pclk2x), // input
                .addr_a     ({hist_bank_pclk,hist_rwaddr[9:0]}), // input[10:0] 
475
                .data_in_a  (inc_sat),      // input[31:0] 
476 477 478 479 480 481 482 483 484 485 486 487 488 489
                .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] 
490
                .data_in_a  (inc_sat),      // input[31:0] 
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 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658
                .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
659 660 661 662 663

module  sens_histogram_dummy(
    output        hist_rq,
    output [31:0] hist_do,
    output        hist_dv
664 665 666 667
`ifdef DEBUG_RING       
    , output debug_do,
    input    debug_di
`endif         
668 669 670 671
);
    assign         hist_rq = 0;
    assign         hist_do = 0;
    assign         hist_dv = 0;
672 673 674 675
`ifdef DEBUG_RING       
    assign  debug_do =  debug_di;
`endif         
    
676
endmodule