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

module  cmd_seq_mux#(
38 39
    parameter CMDSEQMUX_ADDR =   'h702, // only status control
    parameter CMDSEQMUX_MASK =   'h7ff,
40
    parameter CMDSEQMUX_STATUS = 'h38,
41
    parameter AXI_WR_ADDR_BITS=14
42
)(
Andrey Filippov's avatar
Andrey Filippov committed
43
    input                             mrst,         // global system reset
44 45 46 47 48 49 50 51
    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)
    
52
    // Sensor channel 0
53 54 55 56 57
    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
58
    // Sensor channel 1
59 60 61 62 63
    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
64
    // Sensor channel 2
65 66 67 68 69
    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
70
    // Sensor channel 3
71 72 73 74 75
    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
76
    // mux output
77 78 79 80
    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
81
);
82 83 84 85 86 87 88 89 90
    wire  [3:0] wr_en = {wr_en3 & ~ackn3, wr_en2 & ~ackn2, wr_en1 & ~ackn1, wr_en0 & ~ackn0};
    wire [15:0] pri_one_rr; // round robin priority
    wire  [3:0] pri_one;
    reg   [1:0] chn_r; // last served channel
    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;
91
    
92 93 94 95 96 97 98
    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];
99 100 101 102 103 104 105
    assign rq_any= |wr_en;
    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
106 107
    always @(posedge mclk) begin
        if (mrst)           full_r <= 0;
108 109 110
        else if (rq_any)    full_r <= 1;
        else if (ackn_out)  full_r <= 0;
        
Andrey Filippov's avatar
Andrey Filippov committed
111
        if (mrst)           ackn_r <=0;
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
        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
    
        if (ackn_w) begin
            chn_r <= pri_enc_w;
            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
143 144 145 146 147 148 149 150 151 152 153 154
    
    // 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
155
        .rst        (1'b0),        //rst),         // input
156
        .clk        (mclk),        // input
Andrey Filippov's avatar
Andrey Filippov committed
157
        .srst       (mrst),        // input
158 159
        .ad         (cmd_ad),      // input[7:0] 
        .stb        (cmd_stb),     // input
Andrey Filippov's avatar
Andrey Filippov committed
160
        .addr       (),            // output[0:0] 
161
        .data       (cmd_data),    // output[31:0] 
Andrey Filippov's avatar
Andrey Filippov committed
162
        .we         (cmd_status)   // output
163
    );
164
                      
165 166 167 168 169
    status_generate #(
        .STATUS_REG_ADDR     (CMDSEQMUX_STATUS),
        .PAYLOAD_BITS        (18),
        .REGISTER_STATUS     (1)
    ) status_generate_cmd_seq_mux_i (
Andrey Filippov's avatar
Andrey Filippov committed
170 171 172 173 174
        .rst           (1'b0),               //rst),         // input
        .clk           (mclk),               // input
        .srst          (mrst),               // input
        .we            (cmd_status),         // input
        .wd            (cmd_data[7:0]),      // input[7:0] 
175
        .status        ({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
176 177 178
        .ad            (status_ad),          // output[7:0] 
        .rq            (status_rq),          // output
        .start         (status_start)        // input
179 180
    );

181 182 183 184


endmodule