sens_gamma.v 16.7 KB
Newer Older
1 2 3
/*******************************************************************************
 * Module: sens_gamma
 * Date:2015-05-24  
4
 * Author: Andrey Filippov     
5 6
 * Description: table based piecewise-linear conversion of 16 -> 8 bit data
 *
7
 * Copyright (c) 2015 Elphel, Inc.
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
 * sens_gamma.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_gamma.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_gamma #(
24 25
    parameter SENS_GAMMA_NUM_CHN =     3, // number of subchannels for his sensor ports (1..4)
    parameter SENS_GAMMA_BUFFER =      0, // 1 - use "shadow" table for clean switching, 0 - single table per channel
26
    parameter SENS_GAMMA_ADDR =        'h338,
27
    parameter SENS_GAMMA_ADDR_MASK =   'h7fc,
28
    parameter SENS_GAMMA_CTRL =        'h0,
29 30 31
    parameter SENS_GAMMA_ADDR_DATA =   'h1, // bit 20 ==1 - table address, bit 20==0 - table data (18 bits)
    parameter SENS_GAMMA_HEIGHT01 =    'h2, // bits [15:0] - height minus 1 of image 0, [31:16] - height-1 of image1
    parameter SENS_GAMMA_HEIGHT2 =     'h3, // bits [15:0] - height minus 1 of image 2 ( no need for image 3)
32 33 34 35 36 37
    parameter SENS_GAMMA_MODE_WIDTH =  5, // does not include trig
    parameter SENS_GAMMA_MODE_BAYER =  0,
    parameter SENS_GAMMA_MODE_PAGE =   2,
    parameter SENS_GAMMA_MODE_EN =     3,
    parameter SENS_GAMMA_MODE_REPET =  4,
    parameter SENS_GAMMA_MODE_TRIG =   5
38
) (
Andrey Filippov's avatar
Andrey Filippov committed
39
//    input         rst,
40 41 42 43 44 45 46 47 48 49 50
    input         pclk,   // global clock input, pixel rate (96MHz for MT9P006)
    //input         en,     //    @(posedge pclk)      // Enable. Should go active before or with the first hact going active.
                                       // when low will also reset MSB of addresses - buffer page for ping-pong access.
                                       // SDRAM ch1 should be enabled earler to have data ready in the buffer
                                       // When going low will mask input hact, finish pending data->SDRAM and quit
                                       // So normal sequence is:
                                       //   1 - program (end enable) SDRAM channels 0 and 1, channel 1 will start reading
                                       //   2 - wait for frame sync and enable "en"
                                       //   3 (optional) - after frame is over (before the first hact of the next one)
                                       //      turn "en" off. If needed to restart - go to step 1 to keep buffer pages in sync.
    
Andrey Filippov's avatar
Andrey Filippov committed
51 52 53
    input         mrst,        // @mclk sync reset
    input         prst,        // @mclk sync reset
    
54 55 56 57
    input  [15:0] pxd_in, //    @(posedge pclk)
    input         hact_in,
    input         sof_in,    // start of frame, single pclk, input
    input         eof_in,   // end of frame
Andrey Filippov's avatar
Andrey Filippov committed
58 59
    input         trig_in,  // external trigger to process a single frame. May be unused (grounded) as there
                            // is a software trigger option implemented
60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
    output [7:0]  pxd_out,
    output        hact_out,
    output        sof_out,    // start of frame, single pclk, output
    output        eof_out,   // end of frame

    // programming interface
    input         mclk,        // global clock, half DDR3 clock, synchronizes all I/O through the command port
    input   [7:0] cmd_ad,      // byte-serial command address/data (up to 6 bytes: AL-AH-D0-D1-D2-D3 
    input         cmd_stb     // strobe (with first byte) for the command a/d
);
    wire    [1:0] cmd_a;
    wire   [31:0] cmd_data;
    wire          cmd_we;
//    wire          set_status_w;
    wire          set_ctrl_w;
    wire          set_taddr_w;
    wire          set_tdata_w;
77 78 79 80 81 82 83
    wire          set_height01_w;
    wire          set_height2_w;
    reg           set_tdata_r;
    reg    [3:0]  set_tdata_ram;
    reg    [17:0] tdata;
//    wire          set_taddr_data_w;
    reg    [12:0] taddr; // to high bits - select channnel (in buffered mode), in nion-buffered - 1 bit less, only 10 bits each table
84 85
    reg [SENS_GAMMA_MODE_WIDTH-1:0] mode=0;
    reg [SENS_GAMMA_MODE_WIDTH-1:0] mode_mclk=0;
86 87 88 89 90
    
    reg    [15:0] height0_m1; // set @ posedge mclk, used at pclk, but should be OK
    reg    [15:0] height1_m1;
    reg    [15:0] height2_m1;
    
91 92 93 94 95
    wire    [1:0] bayer;
    wire          table_page; //part of the mode register
    wire          en_input;
    wire          repet_mode;
    
96 97 98 99 100 101 102 103 104
    reg     [1:0] sensor_subchn; // select sensor from the multiplexed ones
    reg           sof_r;
    reg           inc_line;
    reg    [15:0] line_cntr;     // count image lines to switch to next subchannels
    wire    [3:0] table_re;
    reg     [3:0] table_regen;
    wire    [1:0] ram_chn;
    reg     [1:0] ram_chn_d;
    reg     [1:0] ram_chn_d2;
105 106 107 108 109 110
    
    reg           bayer_nset; // set color to bayer (start of frame up to first hact) when zero
    wire          sync_bayer; // at the beginning of the line - sync color to bayer
    reg     [1:0] color; // for selecting page in a gamma table
    reg           bayer0_latched; // latch bayer[0] at the beginning of first line
//    reg           hact_m;
111
    reg     [4:0] hact_d; // combine several delays?
112 113 114 115 116 117 118
//    reg           en_d;
    reg     [7:0] cdata;   //8-bit pixel data after "curves"
// modified table data to increase precision. table_base[9:0] is now 10 bits (2 extra).
// The 10-bit interpolation will be rounded to 8 bits at the very last stage
// 8 bit table_diff will be "floating point" with the following format
// now "signed" is 2's complement, was sign, abs() before

119 120
    reg     [7:0] table_diff_m; // 8 msbs in table word - msb - sign (0 plus, 1 - minus), other 7 bits - +/-127 difference to the next value
    reg     [9:0] table_base_m; // 10 lsbs in the table - base value, will be corrected using table_diff and input data lsbs (2 for now)
121 122 123 124 125 126 127 128 129
    wire   [35:0] table_mult;
    
// register decoded memory output
    reg     [9:0] table_base;
    reg    [10:0] table_diff;
    reg    [17:7] table_mult_r;
    reg    [ 9:0] table_base_r;
    
    wire    [9:0] interp_data;
130 131
    wire    [7:0] pxd_in_d3;
    reg     [7:0] pxd_in_r4; // register to be absorbed in mpy
132 133 134 135 136
    
    reg           vblank;    // from sof to first hact
    reg           pend_trig; // pending trigger (if trig came outside of vblank 
    wire          sof_masked;
    reg           frame_run;
Andrey Filippov's avatar
Andrey Filippov committed
137 138
    wire          trig_soft;
    wire          trig;
139 140 141 142 143 144
    wire   [10:0] table_raddr;
    wire   [17:0] table_rdata0;
    wire   [17:0] table_rdata1;
    wire   [17:0] table_rdata2;
    wire   [17:0] table_rdata3;
    wire   [17:0] table_rdata;
145 146

    assign        pxd_out = cdata;
147
    assign        hact_out = hact_d[4];
148 149 150
    
    assign set_ctrl_w =   cmd_we && (cmd_a == SENS_GAMMA_CTRL );
//    assign set_status_w = cmd_we && (cmd_a == SENS_GAMMA_STATUS );
151 152 153 154
//    assign set_taddr_w =  cmd_we && (cmd_a == SENS_GAMMA_TADDR );
//    assign set_tdata_w =  cmd_we && (cmd_a == SENS_GAMMA_TDATA );
    assign set_taddr_w =  cmd_we && (cmd_a == SENS_GAMMA_ADDR_DATA ) && cmd_data[20];
    assign set_tdata_w =  cmd_we && (cmd_a == SENS_GAMMA_ADDR_DATA ) && !cmd_data[20];
155
    
156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171
    assign set_height01_w =  cmd_we && (cmd_a == SENS_GAMMA_HEIGHT01 );
    assign set_height2_w =  cmd_we && (cmd_a == SENS_GAMMA_HEIGHT2 );
    
    assign ram_chn= SENS_GAMMA_BUFFER ? sensor_subchn: {1'b0, sensor_subchn[1]};
    assign table_re= {4{hact_in}} & { ram_chn[1] &  ram_chn[0],
                                      ram_chn[1] & ~ram_chn[0],
                                     ~ram_chn[1] &  ram_chn[0],
                                     ~ram_chn[1] & ~ram_chn[0]};
    assign table_raddr= SENS_GAMMA_BUFFER ?
                             {table_page,color[1:0],pxd_in[15:8]}:
                             {ram_chn[0],color[1:0],pxd_in[15:8]};

// TODO: register data    
    assign table_rdata= ram_chn_d2[1]?
                            (ram_chn_d2[0]?table_rdata3:table_rdata2):
                            (ram_chn_d2[0]?table_rdata1:table_rdata0);
172
//    assign {table_diff_w[7:0],table_base_w[9:0]} = table_rdata;
Andrey Filippov's avatar
Andrey Filippov committed
173 174 175 176 177

    assign bayer =        mode[SENS_GAMMA_MODE_BAYER +: 2];
    assign table_page =   mode[SENS_GAMMA_MODE_PAGE]; // TODO: re-assign?
    assign en_input =     mode[SENS_GAMMA_MODE_EN]; 
    assign repet_mode =   mode[SENS_GAMMA_MODE_REPET]; // TODO: re-assign?
178 179 180
    
    assign sync_bayer=hact_d[1] && ~hact_d[2];
    assign interp_data[9:0] = table_base_r[9:0]+table_mult_r[17:8]+table_mult_r[7]; //round
181
    assign table_mult=table_diff*{1'b0,pxd_in_r4[7:0]}; // 11 bits, signed* 9 bits, positive
182 183
    
    assign sof_masked= sof_in && (pend_trig || repet_mode) && en_input;
Andrey Filippov's avatar
Andrey Filippov committed
184
    assign trig = trig_in || trig_soft;
Andrey Filippov's avatar
Andrey Filippov committed
185 186
    always @ (posedge mclk) begin
        if     (mrst)         tdata <= 0;
187 188
        else if (set_taddr_w) tdata <= cmd_data[17:0];
    
Andrey Filippov's avatar
Andrey Filippov committed
189 190
        if (mrst) set_tdata_r <= 0;
        else      set_tdata_r <= set_tdata_w;
191
        
Andrey Filippov's avatar
Andrey Filippov committed
192
        if     (mrst)         taddr <= 0;
193 194 195
        else if (set_taddr_w) taddr <= cmd_data[12:0];
        else if (set_tdata_r) taddr <= taddr + 1;
        
Andrey Filippov's avatar
Andrey Filippov committed
196
        if     (mrst)         mode_mclk <= 0;
197
        else if (set_ctrl_w)  mode_mclk <= cmd_data[SENS_GAMMA_MODE_WIDTH-1:0];
198
        
Andrey Filippov's avatar
Andrey Filippov committed
199 200
        if (mrst) set_tdata_ram <=0;
        else      set_tdata_ram <= {4{set_tdata_w}} &
201 202 203 204
                                  { taddr[12] &  taddr[11],
                                    taddr[12] & ~taddr[11],
                                   ~taddr[12] &  taddr[11],
                                   ~taddr[12] & ~taddr[11]};
Andrey Filippov's avatar
Andrey Filippov committed
205
        if      (mrst)           height0_m1 <= 0;
206 207
        else if (set_height01_w) height0_m1 <= cmd_data[15:0];
                                   
Andrey Filippov's avatar
Andrey Filippov committed
208
        if      (mrst)           height1_m1 <= 0;
209 210
        else if (set_height01_w) height1_m1 <= cmd_data[31:16];
                                   
Andrey Filippov's avatar
Andrey Filippov committed
211
        if      (mrst)           height2_m1 <= 0;
212 213 214
        else if (set_height2_w)  height2_m1 <= cmd_data[15:0];
                                   
                                   
215
    end 
216

Andrey Filippov's avatar
Andrey Filippov committed
217 218
    always @ (posedge pclk) begin
        if (prst) begin
219
            mode <= 0;
220
            hact_d[4:0] <= 0;
221 222 223 224 225 226 227 228 229 230
            bayer_nset <= 0;
            bayer0_latched <= 0;
            color[1:0] <= 0;
            cdata[7:0] <= 0;
            vblank     <= 0;  // from sof to first hact
            pend_trig  <= 0; // pending trigger (if trig came outside of vblank
            frame_run <= 0; 
            
        end else begin
            mode <= mode_mclk;
231
            hact_d[4:0] <= {hact_d[3:0],hact_in};
232 233 234 235
            bayer_nset <= frame_run && (bayer_nset || hact_in);
            bayer0_latched <= bayer_nset? bayer0_latched:bayer[0];
            color[1:0] <= { bayer_nset? (sync_bayer ^ color[1]):bayer[1] ,
                           (bayer_nset &&(~sync_bayer))?~color[0]:bayer0_latched };
236
            pxd_in_r4 <= pxd_in_d3;
237 238 239 240 241 242 243 244 245 246
            cdata[7:0] <= interp_data[9:2];
            vblank <= sof_in || (vblank && !hact_in);
            pend_trig <= (trig && !vblank) || (pend_trig && !sof_in);  
            frame_run <= sof_masked || (frame_run && !eof_in);
        end
        
        
    end
    
  always @ (posedge pclk) begin
247 248 249 250 251
    {table_diff_m[7:0],table_base_m[9:0]} <= table_rdata;
    table_base[9:0]  <= table_base_m[9:0];
    table_diff[10:0] <= table_diff_m[7]?
                          {table_diff_m[6:0],4'b0}:
                          {{4{table_diff_m[6]}},table_diff_m[6:0]}; 
252 253
    table_mult_r[17:7] <= table_mult[17:7];
    table_base_r[ 9:0] <= table_base[ 9:0];
254 255 256 257 258 259 260 261 262 263 264 265 266 267 268
    
    table_regen <= table_re;
    ram_chn_d   <= ram_chn;
    ram_chn_d2  <= ram_chn_d;
    
    inc_line <= hact_d[0] && !hact_in && (sensor_subchn < SENS_GAMMA_NUM_CHN);
    
    sof_r <= sof_in;
    
    if      (sof_r)                        sensor_subchn <= 0;
    else if (inc_line && (line_cntr == 0)) sensor_subchn <= sensor_subchn+1;
    
    if      (sof_r)                        line_cntr <= height0_m1;
    else if (inc_line && (line_cntr == 0)) line_cntr <= (sensor_subchn ==0)? height1_m1: height2_m1;
    
269 270 271 272 273 274 275 276 277 278
  end
    
    
    cmd_deser #(
        .ADDR        (SENS_GAMMA_ADDR),
        .ADDR_MASK   (SENS_GAMMA_ADDR_MASK),
        .NUM_CYCLES  (6),
        .ADDR_WIDTH  (2),
        .DATA_WIDTH  (32)
    ) cmd_deser_sens_io_i (
Andrey Filippov's avatar
Andrey Filippov committed
279
        .rst         (1'b0), // rst), // input
280
        .clk         (mclk), // input
Andrey Filippov's avatar
Andrey Filippov committed
281
        .srst        (mrst), // input
282 283 284 285 286 287
        .ad          (cmd_ad), // input[7:0] 
        .stb         (cmd_stb), // input
        .addr        (cmd_a), // output[15:0] 
        .data        (cmd_data), // output[31:0] 
        .we          (cmd_we) // output
    );
288

289 290 291 292
    dly_16 #(
        .WIDTH(8)
    ) dly_16_pxd_i (
        .clk (pclk),        // input
Andrey Filippov's avatar
Andrey Filippov committed
293
        .rst (prst),        // input
294
        .dly (4'd3),           // input[3:0] 
295
        .din (pxd_in[7:0]), // input[0:0] 
296
        .dout(pxd_in_d3)    // output[0:0] 
297 298 299 300 301 302
    );

    dly_16 #(
        .WIDTH(2)
    ) dly_16_sof_eof_i (
        .clk (pclk),        // input
Andrey Filippov's avatar
Andrey Filippov committed
303
        .rst (prst),         // input
304
        .dly (4'd4),           // input[3:0] 
305 306 307
        .din ({eof_in, sof_masked}), // input[0:0] 
        .dout({eof_out,sof_out})    // output[0:0] 
    );
Andrey Filippov's avatar
Andrey Filippov committed
308
    pulse_cross_clock trig_soft_i (
Andrey Filippov's avatar
Andrey Filippov committed
309
        .rst       (mrst),
Andrey Filippov's avatar
Andrey Filippov committed
310 311 312 313 314
        .src_clk   (mclk),
        .dst_clk   (pclk),
        .in_pulse  (cmd_data[SENS_GAMMA_MODE_TRIG] && set_ctrl_w),
        .out_pulse (trig_soft),
        .busy      ());
315

316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334
    // channel0 (or 0,1 - always present)
    ramp_var_w_var_r #(
        .REGISTERS    (1), // try to delay i2c_byte_start by one more cycle
        .LOG2WIDTH_WR (4),
        .LOG2WIDTH_RD (4),
        .DUMMY        (0)
    ) gamma_table0_i (
        .rclk         (pclk), // input
        .raddr        (table_raddr), // input[11:0] 
        .ren          (table_re[0]), // input TODO: add "en"?
        .regen        (table_regen[0]), // input
        .data_out     (table_rdata0), // output[7:0] 
        .wclk         (mclk), // input
        .waddr        (taddr[10:0]), // input[9:0] 
        .we           (set_tdata_ram[0]), // input
        .web          (8'hff), // input[7:0] 
        .data_in      (tdata) // input[31:0] 
    );
    // Optionally generated/ replaced by dummy
335 336 337
    ramp_var_w_var_r #(
        .REGISTERS    (1), // try to delay i2c_byte_start by one more cycle
        .LOG2WIDTH_WR (4),
338 339 340
        .LOG2WIDTH_RD (4),
        .DUMMY        (!((SENS_GAMMA_NUM_CHN > 1) && ((SENS_GAMMA_NUM_CHN > 2) || SENS_GAMMA_BUFFER)))
    ) gamma_table1_i (
341
        .rclk         (pclk), // input
342 343 344
        .raddr        (table_raddr), // input[11:0] 
        .ren          (table_re[1]), // input TODO: add "en"?
        .regen        (table_regen[1]), // input
345
        .data_out     (table_rdata1), // output[17:0] 
346
        .wclk         (mclk), // input
347 348
        .waddr        (taddr[10:0]), // input[9:0] 
        .we           (set_tdata_ram[1]), // input
349
        .web          (8'hff), // input[7:0] 
350
        .data_in      (tdata) // input[17:0] 
351 352
    );

353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387
    ramp_var_w_var_r #(
        .REGISTERS    (1), // try to delay i2c_byte_start by one more cycle
        .LOG2WIDTH_WR (4),
        .LOG2WIDTH_RD (4),
        .DUMMY        (!(SENS_GAMMA_BUFFER && (SENS_GAMMA_NUM_CHN > 2)))
    ) gamma_table2_i (
        .rclk         (pclk), // input
        .raddr        (table_raddr), // input[11:0] 
        .ren          (table_re[2]), // input TODO: add "en"?
        .regen        (table_regen[2]), // input
        .data_out     (table_rdata2), // output[7:0] 
        .wclk         (mclk), // input
        .waddr        (taddr[10:0]), // input[9:0] 
        .we           (set_tdata_ram[2]), // input
        .web          (8'hff), // input[7:0] 
        .data_in      (tdata) // input[31:0] 
    );

    ramp_var_w_var_r #(
        .REGISTERS    (1), // try to delay i2c_byte_start by one more cycle
        .LOG2WIDTH_WR (4),
        .LOG2WIDTH_RD (4),
        .DUMMY        (!(SENS_GAMMA_BUFFER && (SENS_GAMMA_NUM_CHN > 3)))
    ) gamma_table3_i (
        .rclk         (pclk), // input
        .raddr        (table_raddr), // input[11:0] 
        .ren          (table_re[3]), // input TODO: add "en"?
        .regen        (table_regen[3]), // input
        .data_out     (table_rdata3), // output[7:0] 
        .wclk         (mclk), // input
        .waddr        (taddr[10:0]), // input[9:0] 
        .we           (set_tdata_ram[3]), // input
        .web          (8'hff), // input[7:0] 
        .data_in      (tdata) // input[31:0] 
    );
388 389 390

endmodule