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

module  scheduler16 #(
Andrey Filippov's avatar
Andrey Filippov committed
37 38
    parameter width=16, // counter number of bits
    parameter n_chn=16  // number of channels
39
)(
Andrey Filippov's avatar
Andrey Filippov committed
40
    input             mrst,
41
    input             clk,
Andrey Filippov's avatar
Andrey Filippov committed
42 43 44
    input [n_chn-1:0] chn_en,    // channel enable mask  
    input [n_chn-1:0] want_rq,   // both want_rq and need_rq should go inactive after being granted  
    input [n_chn-1:0] need_rq,
Andrey Filippov's avatar
Andrey Filippov committed
45
    input             en_schedul,    // needs to be disabled before next access can be scheduled
46 47
    output            need,      // granted access is "needed" one, not just "wanted"
    output            grant,     // single-cycle granted channel access
Andrey Filippov's avatar
Andrey Filippov committed
48
    output      [3:0] grant_chn, // granted  channel number, valid with grant, stays valid until en_schedul is deasserted
49 50 51 52
    input       [3:0] pgm_addr,  // channel address to program priority
    input [width-1:0] pgm_data,  // priority data for the channel
    input             pgm_en     // enable programming priority data (use different clock?)
);
Andrey Filippov's avatar
Andrey Filippov committed
53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
    reg [width*n_chn-1:0] pri_reg; // priorities for each channel (start values for priority counters)
    reg       [n_chn-1:0] want_conf, need_conf,need_want_conf,need_want_conf_d;
    wire      [n_chn-1:0] want_set,need_set;
//    reg       [n_chn-1:0] want_set_r,need_set_r;
    reg       [n_chn-1:0] want_need_set_r;
    reg                   need_r, need_r2;
    reg [width*n_chn-1:0] sched_state; // priority counters for each channel
    wire                  need_some=|(need_rq & chn_en);
    wire      [n_chn-1:0] next_want_conf,next_need_conf;
    wire      [n_chn-1:0] need_want_conf_w;
    wire            [3:0] index; // channel index to select
    wire                  index_valid; // selected index valid ("needed" or "wanted")
    reg                   grant_r;      // 1 cycle long
    reg                   grant_sent; // turns on after grant, until en_schedul is de-asserted
    reg             [3:0] grant_chn_r;
    wire                  grant_w;
69 70
    assign grant=grant_r;
    assign grant_chn=grant_chn_r;
Andrey Filippov's avatar
Andrey Filippov committed
71 72
    assign grant_w=en_schedul && index_valid && !grant_sent && !grant;
// Setting priority for each channel    
73 74
    generate
        genvar i;
Andrey Filippov's avatar
Andrey Filippov committed
75
        for (i=0;i<n_chn;i=i+1) begin: pri_reg_block
Andrey Filippov's avatar
Andrey Filippov committed
76 77
            always @ (posedge clk) begin
                if      (mrst)                    pri_reg[width*i +: width] <= 0;
78 79 80 81 82
                else if (pgm_en && (pgm_addr==i)) pri_reg[width*i +: width] <= pgm_data; 
            end
        end
    endgenerate        

Andrey Filippov's avatar
Andrey Filippov committed
83 84 85
// priority 1-hot encoders to make sure only one want/need request is "confirmed" in each clock cycle
// TODO: Make pri1hot16 parameter-configurable to be able to change priorities later
    pri1hot16 i_pri1hot16_want( // priority encoder, 1-hot output (lowest bit has highest priority)
86
        .in(want_rq & ~want_conf & chn_en),
87 88 89
        .out(want_set),
        .some());
    pri1hot16 i_pri1hot16_need(
90
        .in(need_rq & ~need_conf & chn_en),
91 92 93
        .out(need_set),
        .some());
        
Andrey Filippov's avatar
Andrey Filippov committed
94 95 96
    assign next_want_conf=  (want_conf &  want_rq & chn_en) | want_set;
    assign next_need_conf=  (need_conf &  need_rq & chn_en) | need_set;
    assign need_want_conf_w=need_some? next_need_conf: next_want_conf;
Andrey Filippov's avatar
Andrey Filippov committed
97 98
    always @(posedge clk) begin
        if (mrst) begin
99 100 101 102 103
            want_conf <= 0;
            need_conf <= 0;
        end else begin
            want_conf <= next_want_conf;
            need_conf <= next_need_conf;
Andrey Filippov's avatar
Andrey Filippov committed
104 105
            need_want_conf  <= need_want_conf_w; // need_some? next_need_conf: next_want_conf; 
            need_want_conf_d <= need_want_conf &  need_want_conf_w; // delay for on, no delay for off
106 107 108
        end
    end
    always @ (posedge clk) begin
Andrey Filippov's avatar
Andrey Filippov committed
109 110 111 112 113
//        want_set_r<=want_set;
//        need_set_r<=need_set;
        want_need_set_r <= want_set | need_set;
        need_r  <= need_some;
        need_r2 <= need_r;
114 115
    end
    // TODO: want remains, need is removed (both need and want should be deactivated on grant!)
116
    // Block that sets initial process state and increments it on every change of the requests
117 118 119
    generate
        genvar i1;
        for (i1=0;i1<16;i1=i1+1) begin: sched_state_block
120 121
//            always @ (posedge rst or posedge clk) begin
            always @ (posedge clk) begin
Andrey Filippov's avatar
Andrey Filippov committed
122 123 124 125 126
//                if (rst) sched_state[width*i1 +: width] <= 0; // not needed?
//                else
                begin
//                    if (want_set_r[i1] || need_set_r[i1])          sched_state[width*i1 +: width] <= pri_reg[width*i1 +: width];
                    if (want_need_set_r[i1])          sched_state[width*i1 +: width] <= pri_reg[width*i1 +: width];
127
                    // increment, but do not roll over
Andrey Filippov's avatar
Andrey Filippov committed
128
                    else if (&sched_state[width*i1 +: width] == 0) sched_state[width*i1 +: width] <= sched_state[width*i1 +: width]+1; 
129 130 131 132 133 134
                end 
            end
        end
    endgenerate
    // Select the process to run
    index_max_16 #(width) i_index_max_16(
Andrey Filippov's avatar
Andrey Filippov committed
135 136 137 138 139 140 141
        .clk      (clk),
        .values   (sched_state),
        .mask     (need_want_conf_d),
        .need_in  (need_r2),
        .index    (index[3:0]),
        .valid    (index_valid),
        .need_out (need));
Andrey Filippov's avatar
Andrey Filippov committed
142 143
    always @(posedge clk) begin
        if (mrst) begin
144 145 146 147
            grant_r <=0;
            grant_sent <=0;
            grant_chn_r <=0;
        end else begin
Andrey Filippov's avatar
Andrey Filippov committed
148 149
            grant_r    <= grant_w; // en_schedul && index_valid && !grant_sent;
            grant_sent <= (grant_sent && en_schedul) || grant_r;
150 151 152 153 154 155
            if (grant_w) grant_chn_r <= index[3:0];   
        end
    end

endmodule