mcntrl_ps_pio.v 11.8 KB
Newer Older
1 2 3
/*******************************************************************************
 * Module: mcntrl_ps_pio
 * Date:2015-01-27  
4
 * Author: Andrey Filippov     
5 6 7
 * Description: Read/write channels to DDR3 memory with software-programmable
 * command sequence
 *
8
 * Copyright (c) 2015 Elphel, Inc.
9 10 11 12 13 14 15 16 17 18 19 20 21 22
 * mcntrl_ps_pio.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.
 *
 *  mcntrl_ps_pio.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
23
`include "system_defines.vh" 
Andrey Filippov's avatar
Andrey Filippov committed
24
`undef DEBUG_FIFO
25
module  mcntrl_ps_pio#(
26 27 28
    parameter MCNTRL_PS_ADDR=                    'h100,
    parameter MCNTRL_PS_MASK=                    'h3e0, // both channels 0 and 1
    parameter MCNTRL_PS_STATUS_REG_ADDR=         'h2,
29 30 31 32
    parameter MCNTRL_PS_EN_RST=                  'h0,
    parameter MCNTRL_PS_CMD=                     'h1,
    parameter MCNTRL_PS_STATUS_CNTRL=            'h2
)(
Andrey Filippov's avatar
Andrey Filippov committed
33
    input                        mrst,
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
    input                        mclk,
// 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,     // byte-wide address/data
    output                       status_rq,     // request to send downstream (last byte with rq==0)
    input                        status_start,   // acknowledge of address (first byte) from downsteram   
    
// buffers R/W access 
// read port 0   
    input                        port0_clk,
    input                        port0_re,
    input                        port0_regen, 
    input                [9:0]   port0_addr, // includes page
    output              [31:0]   port0_data,
// write port 1
    input                        port1_clk,
    input                        port1_we,
    input                [9:0]   port1_addr, // includes page
    input               [31:0]   port1_data,
// memory controller interface
// read port 0   
57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
    output reg                   want_rq,
    output reg                   need_rq,
    input                        channel_pgm_en, 
    output               [9:0]   seq_data, // only address 
    output                       seq_set,
    input                        seq_done,
    input                        buf_wr,
    input                        buf_wpage_nxt,
    input                        buf_run,  // @ posedge, use to force page nimber in the buffer (use fifo)
    input                        buf_wrun, // @ negedge, use to force page nimber in the buffer (use fifo)
    
    input               [63:0]   buf_wdata,
    input                        buf_rpage_nxt,
    input                        buf_rd, //buf_rd_chn1,
    output              [63:0]   buf_rdata // buf_rdata_chn1 
72
);
73
 localparam CMD_WIDTH=15;
74
 localparam CMD_FIFO_DEPTH=4;
75 76 77 78
 localparam PAGE_FIFO_DEPTH  = 4;// fifo depth to hold page numbers for channels (2 bits should be OK now)
 localparam PAGE_CNTR_BITS = 4;
 
 reg [PAGE_CNTR_BITS-1:0] pending_pages; 
79

Andrey Filippov's avatar
Andrey Filippov committed
80 81

 wire               [4:0] cmd_a; // just to compare
82
 wire              [31:0] cmd_data;
83 84 85 86 87 88 89 90 91 92 93 94 95
 wire                     cmd_we;
 wire               [1:0] status_data;
 
 wire     [CMD_WIDTH-1:0] cmd_out; 
 wire                     cmd_nempty;
 wire                     cmd_half_full; // to status bit

// decoded commands
 wire                     set_cmd_w;
 wire                     set_status_w;
 wire                     set_en_rst; // set enable, reset register
 reg                [1:0] en_reset;//
 wire                     chn_rst = ~en_reset[0]; // resets command, including fifo;
96
 wire                     chn_en = &en_reset[1];   // enable requests by channel (continue ones in progress)
97
// reg                      mem_run;              // sequencer pgm granted and set, waiting/executing memory transfer to/from buffur 0/1
98
 wire                     busy;
99
 wire                     short_busy; // does not include memory transaction
100
 wire                     start;
101
 //reg                [1:0] page;
102
 reg                [1:0] cmd_set_d;
103 104 105 106
// command bit fields
 wire               [9:0] cmd_seq_a= cmd_out[9:0];
 wire               [1:0] cmd_page=  cmd_out[11:10];
 wire                     cmd_need=  cmd_out[12];
107
 wire                     cmd_wr= cmd_out[13]; // chn=   cmd_out[13]; command write, not read
108
 wire                     cmd_wait=  cmd_out[14]; // wait cmd finished before proceeding
109
 reg                      cmd_set;
110 111
 reg                      cmd_wait_r;
 
112
 wire               [1:0] page_out;
113 114
 reg                      nreset_page_fifo;
 reg                      nreset_page_fifo_neg;
115 116 117 118 119 120 121 122 123 124 125 126

wire cmd_wr_out;
reg     [1:0] page_out_r;
reg     [1:0] page_out_r_negedge;
reg           page_r_set;
reg           page_w_set_early;
reg           page_w_set_early_negedge;
reg           en_page_w_set;
reg           page_w_set_negedge;



127
 
128 129
// assign short_busy= want_rq || need_rq ||want_rq1 || need_rq1 || cmd_set; // cmd_set - advance FIFO
 assign short_busy= want_rq || need_rq || cmd_set; // cmd_set - advance FIFO
130 131
 assign busy= short_busy || (pending_pages != 0); //  mem_run;
 assign start= chn_en && !short_busy && cmd_nempty && ((pending_pages == 0) || !cmd_wait_r); //(!mem_run || !cmd_wait_r); // do not wait memory transaction if wait 
132 133
 assign seq_data= cmd_seq_a;
 assign seq_set=cmd_set;
134 135 136 137
 assign status_data=   {cmd_half_full,cmd_nempty | busy};
 assign set_cmd_w =    cmd_we && (cmd_a== MCNTRL_PS_CMD);
 assign set_status_w = cmd_we && (cmd_a== MCNTRL_PS_STATUS_CNTRL);
 assign set_en_rst =   cmd_we && (cmd_a== MCNTRL_PS_EN_RST);
138
 //PAGE_CNTR_BITS
Andrey Filippov's avatar
Andrey Filippov committed
139
    always @ (posedge mclk) begin
140
    
Andrey Filippov's avatar
Andrey Filippov committed
141
        if      (mrst)                  pending_pages <= 0;
142 143 144 145
        else if (chn_rst)               pending_pages <= 0;
        else if ( cmd_set && !seq_done) pending_pages <= pending_pages + 1;
        else if (!cmd_set &&  seq_done) pending_pages <= pending_pages - 1;
        
Andrey Filippov's avatar
Andrey Filippov committed
146 147 148 149
        if (mrst) nreset_page_fifo <= 0;
        else      nreset_page_fifo <= cmd_nempty | busy;
        
        if      (mrst)           cmd_wait_r <= 0;
150
        else if (channel_pgm_en) cmd_wait_r <= cmd_wait;
Andrey Filippov's avatar
Andrey Filippov committed
151 152
        
        if (mrst)            en_reset <= 0;
153 154
        else if (set_en_rst) en_reset <= cmd_data[1:0];
        
Andrey Filippov's avatar
Andrey Filippov committed
155
        if (mrst) begin
156 157
            want_rq <= 0;
            need_rq <= 0;
158
        end else if (chn_rst || channel_pgm_en) begin
159 160
            want_rq <= 0;
            need_rq <= 0;
161
        end else if (start) begin
162 163
            want_rq <= 1; // !cmd_chn;
            need_rq <= cmd_need; // !cmd_chn && cmd_need;
164 165 166
        end
        
        
Andrey Filippov's avatar
Andrey Filippov committed
167
        if (mrst)          cmd_set <= 0;
168 169 170 171
        else if (chn_rst) cmd_set <= 0;
        else              cmd_set <= channel_pgm_en;
        
        
Andrey Filippov's avatar
Andrey Filippov committed
172
        if (mrst)          cmd_set_d <= 0;
173
        else              cmd_set_d <= {cmd_set_d[0],cmd_set & ~cmd_wr}; // only for channel0 (memory read)
174 175
    end
    
176
    
177 178 179
    cmd_deser #(
        .ADDR       (MCNTRL_PS_ADDR),
        .ADDR_MASK  (MCNTRL_PS_MASK),
180
        .NUM_CYCLES (6),
181
        .ADDR_WIDTH (5),
182 183
        .DATA_WIDTH (32)
    ) cmd_deser_mcontr_32bit_i (
Andrey Filippov's avatar
Andrey Filippov committed
184 185 186 187 188 189 190 191
        .rst        (1'b0),       // rst), // input
        .clk        (mclk),       // input
        .srst       (mrst),       // 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
192 193 194 195 196 197
    );

    status_generate #(
        .STATUS_REG_ADDR  (MCNTRL_PS_STATUS_REG_ADDR),
        .PAYLOAD_BITS     (2)
    ) status_generate_i (
Andrey Filippov's avatar
Andrey Filippov committed
198 199 200 201
        .rst              (1'b0),          // rst), // input
        .clk              (mclk),          // input
        .srst             (mrst),          // input
        .we               (set_status_w),  // input
202
        .wd               (cmd_data[7:0]), // input[7:0] 
Andrey Filippov's avatar
Andrey Filippov committed
203 204 205 206
        .status           (status_data),   // input[25:0] 
        .ad               (status_ad),     // output[7:0] 
        .rq               (status_rq),     // output
        .start            (status_start)   // input
207 208 209 210 211 212
    );

fifo_same_clock   #(
    .DATA_WIDTH(CMD_WIDTH),
    .DATA_DEPTH(CMD_FIFO_DEPTH) 
    ) cmd_fifo_i (
Andrey Filippov's avatar
Andrey Filippov committed
213
        .rst       (1'b0),
214
        .clk       (mclk),
Andrey Filippov's avatar
Andrey Filippov committed
215
        .sync_rst  (chn_rst), // synchronously reset fifo;
216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233
        .we        (set_cmd_w),
        .re        (cmd_set),
        .data_in   (cmd_data[CMD_WIDTH-1:0]),
        .data_out  (cmd_out),  //SuppressThisWarning ISExst Assignment to awsize_out ignored, since the identifier is never used
        .nempty    (cmd_nempty),
        .half_full (cmd_half_full)
`ifdef DEBUG_FIFO
        ,
        .under      (waddr_under), // output reg 
        .over       (waddr_over), // output reg
        .wcount     (waddr_wcount), // output[3:0] reg 
        .rcount     (waddr_rcount), // output[3:0] reg 
        .num_in_fifo(waddr_num_in_fifo) // output[3:0] 
`endif         
    );


// Port 0 (read DDR to AXI) buffer
234 235 236
    mcntrl_buf_rd #(
        .LOG2WIDTH_RD(5)
    ) chn0_buf_i (
237 238 239 240 241 242
        .ext_clk      (port0_clk), // input
        .ext_raddr    (port0_addr), // input[9:0] 
        .ext_rd       (port0_re), // input
        .ext_regen    (port0_regen), // input
        .ext_data_out (port0_data), // output[31:0] 
        .wclk         (!mclk), // input
243 244 245
        .wpage_in     (page_out_r_negedge), // page_neg), // input[1:0] 
        .wpage_set    (page_w_set_negedge), //wpage_set_chn0_neg), // input 
        .page_next    (buf_wpage_nxt), // input
246
        .page         (), // output[1:0]
247 248
        .we           (buf_wr), // input
        .data_in      (buf_wdata) // input[63:0] 
249
    );
250 251
    
// Port 1 (write DDR from AXI) buffer
252 253 254
    mcntrl_buf_wr #(
        .LOG2WIDTH_WR(5)
    ) chn1_buf_i (
255 256 257
        .ext_clk      (port1_clk), // input
        .ext_waddr    (port1_addr), // input[9:0] 
        .ext_we       (port1_we), // input
258
        .ext_data_in  (port1_data), // input[31:0] 
259
        .rclk         (mclk), // input
260 261 262
        .rpage_in     (page_out_r), //page), // input[1:0] 
        .rpage_set    (page_r_set), // rpage_set_chn1), // input 
        .page_next    (buf_rpage_nxt), // input
263
        .page         (), // output[1:0]
264 265
        .rd           (buf_rd), // input
        .data_out     (buf_rdata) // output[63:0] 
266 267 268
    );

fifo_same_clock   #(
269
    .DATA_WIDTH(3),
270 271
    .DATA_DEPTH(PAGE_FIFO_DEPTH) 
    ) page_fifo1_i (
Andrey Filippov's avatar
Andrey Filippov committed
272
        .rst       (1'b0),
273
        .clk       (mclk), // posedge
Andrey Filippov's avatar
Andrey Filippov committed
274
        .sync_rst  (mrst || !nreset_page_fifo), // synchronously reset fifo;
275 276 277 278
        .we        (channel_pgm_en),
        .re        (buf_run),
        .data_in   ({cmd_wr,cmd_page}), //page),
        .data_out  ({cmd_wr_out,page_out}),
279 280 281
        .nempty    (), //page_fifo1_nempty),
        .half_full ()
    );
282

Andrey Filippov's avatar
Andrey Filippov committed
283 284
always @ (posedge mclk) begin
    if      (mrst)    page_out_r <= 0;
285
    else if (buf_run) page_out_r <= page_out;
286
    
287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302

end

always @ (posedge mclk) begin
   page_r_set <=        cmd_wr_out && buf_run;  // page_out_r, page_r_set - output to buffer
   page_w_set_early <= !cmd_wr_out && buf_run;
end

always @ (negedge mclk) begin
    nreset_page_fifo_neg <= nreset_page_fifo;
    page_w_set_early_negedge <= page_w_set_early;
    page_out_r_negedge <= page_out_r;
    if (!nreset_page_fifo_neg || buf_wrun) en_page_w_set <= 0;
    else if (page_w_set_early_negedge)     en_page_w_set <= 1;
    page_w_set_negedge <= en_page_w_set && buf_wrun;
end        
303
    
304 305
endmodule