sens_gamma.v 10.6 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 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 95 96 97 98 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 125 126 127 128 129 130 131 132 133 134 135 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 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257
/*******************************************************************************
 * Module: sens_gamma
 * Date:2015-05-24  
 * Author: andrey     
 * Description: table based piecewise-linear conversion of 16 -> 8 bit data
 *
 * Copyright (c) 2015 <set up in Preferences-Verilog/VHDL Editor-Templates> .
 * 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 #(
    parameter SENS_GAMMA_ADDR =        'h338,
    parameter SENS_GAMMA_ADDR_MASK =   'h3fc,
    parameter SENS_GAMMA_CTRL =        'h0,
//    parameter SENS_GAMMA_STATUS =      'h1,
    parameter SENS_GAMMA_TADDR =       'h2,
    parameter SENS_GAMMA_TDATA =       'h3 // 1.. 2^16, 0 - use HACT
//    parameter SENS_GAMMA_STATUS_REG =  'h32
    
) (
    input         rst,
    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.
    
    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
    input         trig,
    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
/*    
    output  [7:0] status_ad,   // status address/data - up to 5 bytes: A - {seq,status[1:0]} - status[2:9] - status[10:17] - status[18:25]
    output        status_rq,   // input request to send status downstream
    input         status_start // Acknowledge of the first status packet byte (address)
*/    
);
    localparam    SENS_GAMMA_MODE_WIDTH=10;
    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;
    reg    [10:0] taddr;
    reg [SENS_GAMMA_MODE_WIDTH-1:0] mode=0;
    reg [SENS_GAMMA_MODE_WIDTH-1:0] mode_mclk=0;
    wire    [1:0] bayer;
    wire          table_page; //part of the mode register
    wire          en_input;
    wire          repet_mode;
    
    
    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;
    reg     [3:0] hact_d; // combine sevaral delays?
//    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

    wire    [7:0] table_diff_w; // 8 msbs in table word - msb - sign (0 plus, 1 - minus), other 7 bits - +/-127 difference to the next value
    wire    [9:0] table_base_w; // 10 lsbs in the table - base value, will be corrected using table_diff and input data lsbs (2 for now)
    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;
    wire    [7:0] pxd_in_d2;
    reg     [7:0] pxd_in_r3; // register to be absorbed in mpy
    
    reg           vblank;    // from sof to first hact
    reg           pend_trig; // pending trigger (if trig came outside of vblank 
    wire          sof_masked;
    reg           frame_run;
    

    assign        pxd_out = cdata;
    assign        hact_out = hact_d[3];
    
    assign set_ctrl_w =   cmd_we && (cmd_a == SENS_GAMMA_CTRL );
//    assign set_status_w = cmd_we && (cmd_a == SENS_GAMMA_STATUS );
    assign set_taddr_w =  cmd_we && (cmd_a == SENS_GAMMA_TADDR );
    assign set_tdata_w =  cmd_we && (cmd_a == SENS_GAMMA_TDATA );
    
    assign bayer =        mode[1:0];
    assign table_page =   mode[2]; // TODO: re-assign?
    assign en_input =     mode[3]; 
    assign repet_mode =   mode[4]; // TODO: re-assign?
    
    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
    assign table_mult=table_diff*{1'b0,pxd_in_r3[7:0]}; // 11 bits, signed* 9 bits, positive
    
    assign sof_masked= sof_in && (pend_trig || repet_mode) && en_input;
    
    always @ (posedge rst or posedge mclk) begin
        if      (rst)         taddr <= 0;
        else if (set_taddr_w) taddr <= cmd_data[10:0];
        else if (set_tdata_w) taddr <= taddr + 1;
        if      (rst)         mode_mclk <= 0;
        else if (set_ctrl_w)  mode_mclk <= cmd_data[SENS_GAMMA_MODE_WIDTH-1:0];
    end 
//    reg           vblank;    // from sof to first hact
//    reg           pend_trig; // pending trigger (if trig came outside of vblank 
    
    always @ (posedge rst or posedge pclk) begin
        if (rst) begin
            mode <= 0;
//            hact_m <= 0;
//            en_d   <= 0;
            hact_d[3:0] <= 0;
            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;
//            hact_m <= hact_in && en;
//            en_d   <= en;
            hact_d[3:0] <= {hact_d[2:0],hact_in};
            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 };
            pxd_in_r3 <= pxd_in_d2;
            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
    table_base[9:0]  <= table_base_w[9:0];
    table_diff[10:0] <= table_diff_w[7]?
                          {table_diff_w[6:0],4'b0}:
                          {{4{table_diff_w[6]}},table_diff_w[6:0]}; 
    table_mult_r[17:7] <= table_mult[17:7];
    table_base_r[ 9:0] <= table_base[ 9:0];
  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 (
        .rst         (rst), // input
        .clk         (mclk), // input
        .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
    );
/*
    status_generate #(
        .STATUS_REG_ADDR(SENS_GAMMA_STATUS_REG),
        .PAYLOAD_BITS(15) // STATUS_PAYLOAD_BITS)
    ) status_generate_sens_io_i (
        .rst        (rst), // input
        .clk        (mclk), // input
        .we         (set_status_w), // input
        .wd         (cmd_data[7:0]), // input[7:0] 
        .status     (status), // input[25:0] 
        .ad         (status_ad), // output[7:0] 
        .rq         (status_rq), // output
        .start      (status_start) // input
    );
*/
    dly_16 #(
        .WIDTH(8)
    ) dly_16_pxd_i (
        .clk (pclk),        // input
        .rst (rst),         // input
        .dly (2),           // input[3:0] 
        .din (pxd_in[7:0]), // input[0:0] 
        .dout(pxd_in_d2)    // output[0:0] 
    );

    dly_16 #(
        .WIDTH(2)
    ) dly_16_sof_eof_i (
        .clk (pclk),        // input
        .rst (rst),         // input
        .dly (3),           // input[3:0] 
        .din ({eof_in, sof_masked}), // input[0:0] 
        .dout({eof_out,sof_out})    // output[0:0] 
    );

//sof_masked
    ramp_var_w_var_r #(
        .REGISTERS    (1), // try to delay i2c_byte_start by one more cycle
        .LOG2WIDTH_WR (4),
        .LOG2WIDTH_RD (4)
    ) i_gamma_table (
        .rclk         (pclk), // input
        .raddr        ({table_page,color[1:0],pxd_in[15:8]}), // input[11:0] 
        .ren          (hact_in), // input TODO: add "en"?
        .regen        (hact_d[0]), // input
        .data_out     ({table_diff_w[7:0],table_base_w[9:0]}), // output[7:0] 
        .wclk         (mclk), // input
        .waddr        (taddr), // input[9:0] 
        .we           (set_tdata_w), // input
        .web          (8'hff), // input[7:0] 
        .data_in      (cmd_data[17:0]) // input[31:0] 
    );


endmodule