scheduler16.v 6.38 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 20 21 22 23
 * 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/> .
 *******************************************************************************/
`timescale 1ns/1ps

module  scheduler16 #(
Andrey Filippov's avatar
Andrey Filippov committed
24 25
    parameter width=16, // counter number of bits
    parameter n_chn=16  // number of channels
26
)(
Andrey Filippov's avatar
Andrey Filippov committed
27
    input             mrst,
28
    input             clk,
Andrey Filippov's avatar
Andrey Filippov committed
29 30 31
    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
32
    input             en_schedul,    // needs to be disabled before next access can be scheduled
33 34
    output            need,      // granted access is "needed" one, not just "wanted"
    output            grant,     // single-cycle granted channel access
Andrey Filippov's avatar
Andrey Filippov committed
35
    output      [3:0] grant_chn, // granted  channel number, valid with grant, stays valid until en_schedul is deasserted
36 37 38 39
    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
40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
    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;
56 57
    assign grant=grant_r;
    assign grant_chn=grant_chn_r;
Andrey Filippov's avatar
Andrey Filippov committed
58 59
    assign grant_w=en_schedul && index_valid && !grant_sent && !grant;
// Setting priority for each channel    
60 61
    generate
        genvar i;
Andrey Filippov's avatar
Andrey Filippov committed
62
        for (i=0;i<n_chn;i=i+1) begin: pri_reg_block
Andrey Filippov's avatar
Andrey Filippov committed
63 64
            always @ (posedge clk) begin
                if      (mrst)                    pri_reg[width*i +: width] <= 0;
65 66 67 68 69
                else if (pgm_en && (pgm_addr==i)) pri_reg[width*i +: width] <= pgm_data; 
            end
        end
    endgenerate        

Andrey Filippov's avatar
Andrey Filippov committed
70 71 72
// 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)
73
        .in(want_rq & ~want_conf & chn_en),
74 75 76
        .out(want_set),
        .some());
    pri1hot16 i_pri1hot16_need(
77
        .in(need_rq & ~need_conf & chn_en),
78 79 80
        .out(need_set),
        .some());
        
Andrey Filippov's avatar
Andrey Filippov committed
81 82 83
    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
84 85
    always @(posedge clk) begin
        if (mrst) begin
86 87 88 89 90
            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
91 92
            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
93 94 95
        end
    end
    always @ (posedge clk) begin
Andrey Filippov's avatar
Andrey Filippov committed
96 97 98 99 100
//        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;
101 102
    end
    // TODO: want remains, need is removed (both need and want should be deactivated on grant!)
103
    // Block that sets initial process state and increments it on every change of the requests
104 105 106
    generate
        genvar i1;
        for (i1=0;i1<16;i1=i1+1) begin: sched_state_block
107 108
//            always @ (posedge rst or posedge clk) begin
            always @ (posedge clk) begin
Andrey Filippov's avatar
Andrey Filippov committed
109 110 111 112 113
//                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];
114
                    // increment, but do not roll over
Andrey Filippov's avatar
Andrey Filippov committed
115
                    else if (&sched_state[width*i1 +: width] == 0) sched_state[width*i1 +: width] <= sched_state[width*i1 +: width]+1; 
116 117 118 119 120 121
                end 
            end
        end
    endgenerate
    // Select the process to run
    index_max_16 #(width) i_index_max_16(
Andrey Filippov's avatar
Andrey Filippov committed
122 123 124 125 126 127 128
        .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
129 130
    always @(posedge clk) begin
        if (mrst) begin
131 132 133 134
            grant_r <=0;
            grant_sent <=0;
            grant_chn_r <=0;
        end else begin
Andrey Filippov's avatar
Andrey Filippov committed
135 136
            grant_r    <= grant_w; // en_schedul && index_valid && !grant_sent;
            grant_sent <= (grant_sent && en_schedul) || grant_r;
137 138 139 140 141 142
            if (grant_w) grant_chn_r <= index[3:0];   
        end
    end

endmodule