cmd_seq_mux.v 9.99 KB
Newer Older
1 2 3 4 5 6 7
/*!
 * <b>Module:</b>cmd_seq_mux
 * @file cmd_seq_mux.v
 * @date 2015-06-29  
 * @author Andrey Filippov     
 *
 * @brief Command multiplexer from 4 channels of frame-based command
8 9
 * sequencers.
 *
10 11 12 13
 * @copyright Copyright (c) 2015 Elphel, Inc.
 *
 * <b>License:</b>
 *
14 15 16 17 18 19 20 21 22 23 24 25
 * cmd_seq_mux.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_seq_mux.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/> .
26 27 28 29 30 31
 *
 * 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"
32
 * files and/or simulating the code, the copyright holders of this Program give
33 34
 * 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
35
 * charge, and there is no dependence on any encrypted modules for simulating of
36 37 38
 * 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.
39
 */
40 41 42
`timescale 1ns/1ps

module  cmd_seq_mux#(
43 44
    parameter CMDSEQMUX_ADDR =   'h702, // only status control
    parameter CMDSEQMUX_MASK =   'h7ff,
45
    parameter CMDSEQMUX_STATUS = 'h38,
46
    parameter AXI_WR_ADDR_BITS=14
47
)(
Andrey Filippov's avatar
Andrey Filippov committed
48
    input                             mrst,         // global system reset
49 50 51 52 53 54 55 56
    input                             mclk,         // global system clock
    // programming interface
    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)
    
57
    // Sensor channel 0
58 59 60 61 62
    input                      [ 3:0] frame_num0,   // @posedge mclk
    input      [AXI_WR_ADDR_BITS-1:0] waddr0,       // write address, valid with wr_en_out
    input                             wr_en0,       // write enable 
    input                      [31:0] wdata0,       // write data, valid with waddr_out and wr_en_out
    output                            ackn0,        // command sequencer address/data accepted
63 64
    input                             is0,          // interrupt status (not masked) 
    input                             im0,          // interrupt mask 
65
    // Sensor channel 1
66 67 68 69 70
    input                      [ 3:0] frame_num1,   // @posedge mclk
    input      [AXI_WR_ADDR_BITS-1:0] waddr1,       // write address, valid with wr_en_out
    input                             wr_en1,       // write enable 
    input                      [31:0] wdata1,       // write data, valid with waddr_out and wr_en_out
    output                            ackn1,        // command sequencer address/data accepted
71 72
    input                             is1,          // interrupt status (not masked) 
    input                             im1,          // interrupt mask 
73
    // Sensor channel 2
74 75 76 77 78
    input                      [ 3:0] frame_num2,   // @posedge mclk
    input      [AXI_WR_ADDR_BITS-1:0] waddr2,       // write address, valid with wr_en_out
    input                             wr_en2,       // write enable 
    input                      [31:0] wdata2,       // write data, valid with waddr_out and wr_en_out
    output                            ackn2,        // command sequencer address/data accepted
79 80
    input                             is2,          // interrupt status (not masked) 
    input                             im2,          // interrupt mask 
81
    // Sensor channel 3
82 83 84 85 86
    input                      [ 3:0] frame_num3,   // @posedge mclk
    input      [AXI_WR_ADDR_BITS-1:0] waddr3,       // write address, valid with wr_en_out
    input                             wr_en3,       // write enable 
    input                      [31:0] wdata3,       // write data, valid with waddr_out and wr_en_out
    output                            ackn3,        // command sequencer address/data accepted
87 88
    input                             is3,          // interrupt status (not masked) 
    input                             im3,          // interrupt mask 
89
    // mux output
90 91 92 93
    output reg [AXI_WR_ADDR_BITS-1:0] waddr_out,    // write address, valid with wr_en_out
    output                            wr_en_out,    // write enable 
    output reg                 [31:0] wdata_out,    // write data, valid with waddr_out and wr_en_out
    input                             ackn_out      // command sequencer address/data accepted
94
);
95 96 97 98
    wire  [3:0] wr_rq = {wr_en3, wr_en2, wr_en1, wr_en0};
//    wire  [3:0] wr_en = {wr_en3 & ~ackn3, wr_en2 & ~ackn2, wr_en1 & ~ackn1, wr_en0 & ~ackn0};
    wire  [3:0] wr_en = wr_rq & ~ackn_r; // write enable antil acknowledged?
    //ackn_r
99 100
    wire [15:0] pri_one_rr; // round robin priority
    wire  [3:0] pri_one;
101
    reg   [1:0] chn_r = 0; // last served channel
102 103 104 105 106
    wire        rq_any;
    wire  [1:0] pri_enc_w;
    reg         full_r;
    wire        ackn_w;  //pre-acknowledge of one of the channels
    reg   [3:0] ackn_r;
107
    
108 109
    wire  [3:0] is = {is3, is2, is1, is0};
    wire  [3:0] im = {im3, im2, im1, im0};
110
    
111 112 113 114 115 116 117
    assign pri_one_rr = {wr_en[3] & ~(|wr_en[2:0]), wr_en[2]&~(|wr_en[1:0]),          wr_en[1] &                  wr_en[0],  wr_en[0],
                         wr_en[3],                  wr_en[2]&~(|wr_en[1:0])&wr_en[3], wr_en[1] & ~  wr_en[3]    & wr_en[0],  wr_en[0] & ~  wr_en[3],
                         wr_en[3] & ~  wr_en[2],    wr_en[2],                         wr_en[1] & ~(|wr_en[3:2]) & wr_en[0],  wr_en[0] & ~(|wr_en[3:2]),
                         wr_en[3] & ~(|wr_en[2:1]), wr_en[2] & ~wr_en[1],             wr_en[1],                              wr_en[0] & ~(|wr_en[3:1])};


    assign pri_one = pri_one_rr[chn_r * 4 +: 4];
118 119
    assign rq_any= |wr_en; // Loop?
//    assign rq_any= |wr_rq;
120 121 122 123 124 125
    assign pri_enc_w ={pri_one[3] | pri_one[2],
                       pri_one[3] | pri_one[1]};
    assign wr_en_out = full_r;
    assign {ackn3, ackn2, ackn1, ackn0} = ackn_r;               
    assign ackn_w = rq_any && (!full_r || ackn_out);
    
Andrey Filippov's avatar
Andrey Filippov committed
126 127
    always @(posedge mclk) begin
        if (mrst)           full_r <= 0;
128 129 130
        else if (rq_any)    full_r <= 1;
        else if (ackn_out)  full_r <= 0;
        
Andrey Filippov's avatar
Andrey Filippov committed
131
        if (mrst)           ackn_r <=0;
132 133 134 135 136 137 138 139
        else                ackn_r <= {4{ackn_w}} & { pri_enc_w[1] &  pri_enc_w[0],
                                                      pri_enc_w[1] & ~pri_enc_w[0],
                                                     ~pri_enc_w[1] &  pri_enc_w[0],
                                                     ~pri_enc_w[1] & ~pri_enc_w[0]};
    end
        
    always @(posedge mclk) begin
    
140 141 142
        if      (mrst)   chn_r <= 0;        // let it always start from 0
        else if (ackn_w) chn_r <= pri_enc_w;
            
143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164
        if (ackn_w) begin
            case (pri_enc_w)
                2'h0:begin
                    waddr_out <= waddr0;
                    wdata_out <= wdata0;
                end 
                2'h1:begin
                    waddr_out <= waddr1;
                    wdata_out <= wdata1;
                end 
                2'h2:begin
                    waddr_out <= waddr2;
                    wdata_out <= wdata2;
                end 
                2'h3:begin
                    waddr_out <= waddr3;
                    wdata_out <= wdata3;
                end 
            endcase
        
        end
    end
165 166 167 168 169 170 171 172 173 174 175 176
    
    // Only command is to program status, status combines frame numbers (4 bit each)
    wire [7:0] cmd_data;
    wire       cmd_status;
    cmd_deser #(
        .ADDR       (CMDSEQMUX_ADDR),
        .ADDR_MASK  (CMDSEQMUX_MASK),
        .NUM_CYCLES (3), // 6), // TODO: Is it OK to specify less bits than on transmit side? Seems yes 
        .ADDR_WIDTH (1),
        .DATA_WIDTH (8) //,32)
        
    ) cmd_deser_32bit_i (
Andrey Filippov's avatar
Andrey Filippov committed
177
        .rst        (1'b0),        //rst),         // input
178
        .clk        (mclk),        // input
Andrey Filippov's avatar
Andrey Filippov committed
179
        .srst       (mrst),        // input
180 181
        .ad         (cmd_ad),      // input[7:0] 
        .stb        (cmd_stb),     // input
Andrey Filippov's avatar
Andrey Filippov committed
182
        .addr       (),            // output[0:0] 
183
        .data       (cmd_data),    // output[31:0] 
Andrey Filippov's avatar
Andrey Filippov committed
184
        .we         (cmd_status)   // output
185
    );
186
                      
187 188
    status_generate #(
        .STATUS_REG_ADDR     (CMDSEQMUX_STATUS),
189
        .PAYLOAD_BITS        (26),
190 191
        .REGISTER_STATUS     (1)
    ) status_generate_cmd_seq_mux_i (
Andrey Filippov's avatar
Andrey Filippov committed
192 193 194 195 196
        .rst           (1'b0),               //rst),         // input
        .clk           (mclk),               // input
        .srst          (mrst),               // input
        .we            (cmd_status),         // input
        .wd            (cmd_data[7:0]),      // input[7:0] 
197
        .status        ({im, is, frame_num3, frame_num2, frame_num1, frame_num0, 2'b0}), // input[18:0] // 2 LSBs - may add "real" status 
Andrey Filippov's avatar
Andrey Filippov committed
198 199 200
        .ad            (status_ad),          // output[7:0] 
        .rq            (status_rq),          // output
        .start         (status_start)        // input
201 202
    );

203 204 205 206


endmodule