mcntrl_ps_pio.v 13.1 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
 * 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/> .
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
 *******************************************************************************/
`timescale 1ns/1ps
36
`include "system_defines.vh" 
Andrey Filippov's avatar
Andrey Filippov committed
37
`undef DEBUG_FIFO
38
module  mcntrl_ps_pio#(
39 40 41
    parameter MCNTRL_PS_ADDR=                    'h100,
    parameter MCNTRL_PS_MASK=                    'h3e0, // both channels 0 and 1
    parameter MCNTRL_PS_STATUS_REG_ADDR=         'h2,
42 43 44 45
    parameter MCNTRL_PS_EN_RST=                  'h0,
    parameter MCNTRL_PS_CMD=                     'h1,
    parameter MCNTRL_PS_STATUS_CNTRL=            'h2
)(
Andrey Filippov's avatar
Andrey Filippov committed
46
    input                        mrst,
47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
    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   
70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
    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 
85
);
86
 localparam CMD_WIDTH=15;
87
 localparam CMD_FIFO_DEPTH=4;
88 89 90 91
 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; 
92

Andrey Filippov's avatar
Andrey Filippov committed
93 94

 wire               [4:0] cmd_a; // just to compare
95
 wire              [31:0] cmd_data;
96 97 98 99 100 101 102 103 104 105 106 107 108
 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;
109
 wire                     chn_en = &en_reset[1];   // enable requests by channel (continue ones in progress)
110
// reg                      mem_run;              // sequencer pgm granted and set, waiting/executing memory transfer to/from buffur 0/1
111
 wire                     busy;
112
 wire                     short_busy; // does not include memory transaction
113
 wire                     start;
114
 //reg                [1:0] page;
115
 reg                [1:0] cmd_set_d;
116 117 118 119
// 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];
120
 wire                     cmd_wr= cmd_out[13]; // chn=   cmd_out[13]; command write, not read
121
 wire                     cmd_wait=  cmd_out[14]; // wait cmd finished before proceeding
122
 reg                      cmd_set;
123 124
 reg                      cmd_wait_r;
 
125
 wire               [1:0] page_out;
126 127
 reg                      nreset_page_fifo;
 reg                      nreset_page_fifo_neg;
128 129 130 131 132 133 134 135 136 137 138 139

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;



140
 
141 142
// 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
143 144
 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 
145 146
 assign seq_data= cmd_seq_a;
 assign seq_set=cmd_set;
147 148 149 150
 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);
151
 //PAGE_CNTR_BITS
Andrey Filippov's avatar
Andrey Filippov committed
152
    always @ (posedge mclk) begin
153
    
Andrey Filippov's avatar
Andrey Filippov committed
154
        if      (mrst)                  pending_pages <= 0;
155 156 157 158
        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
159 160 161 162
        if (mrst) nreset_page_fifo <= 0;
        else      nreset_page_fifo <= cmd_nempty | busy;
        
        if      (mrst)           cmd_wait_r <= 0;
163
        else if (channel_pgm_en) cmd_wait_r <= cmd_wait;
Andrey Filippov's avatar
Andrey Filippov committed
164 165
        
        if (mrst)            en_reset <= 0;
166 167
        else if (set_en_rst) en_reset <= cmd_data[1:0];
        
Andrey Filippov's avatar
Andrey Filippov committed
168
        if (mrst) begin
169 170
            want_rq <= 0;
            need_rq <= 0;
171
        end else if (chn_rst || channel_pgm_en) begin
172 173
            want_rq <= 0;
            need_rq <= 0;
174
        end else if (start) begin
175 176
            want_rq <= 1; // !cmd_chn;
            need_rq <= cmd_need; // !cmd_chn && cmd_need;
177 178 179
        end
        
        
Andrey Filippov's avatar
Andrey Filippov committed
180
        if (mrst)          cmd_set <= 0;
181 182 183 184
        else if (chn_rst) cmd_set <= 0;
        else              cmd_set <= channel_pgm_en;
        
        
Andrey Filippov's avatar
Andrey Filippov committed
185
        if (mrst)          cmd_set_d <= 0;
186
        else              cmd_set_d <= {cmd_set_d[0],cmd_set & ~cmd_wr}; // only for channel0 (memory read)
187 188
    end
    
189
    
190 191 192
    cmd_deser #(
        .ADDR       (MCNTRL_PS_ADDR),
        .ADDR_MASK  (MCNTRL_PS_MASK),
193
        .NUM_CYCLES (6),
194
        .ADDR_WIDTH (5),
195 196
        .DATA_WIDTH (32)
    ) cmd_deser_mcontr_32bit_i (
Andrey Filippov's avatar
Andrey Filippov committed
197 198 199 200 201 202 203 204
        .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
205 206 207 208 209 210
    );

    status_generate #(
        .STATUS_REG_ADDR  (MCNTRL_PS_STATUS_REG_ADDR),
        .PAYLOAD_BITS     (2)
    ) status_generate_i (
Andrey Filippov's avatar
Andrey Filippov committed
211 212 213 214
        .rst              (1'b0),          // rst), // input
        .clk              (mclk),          // input
        .srst             (mrst),          // input
        .we               (set_status_w),  // input
215
        .wd               (cmd_data[7:0]), // input[7:0] 
Andrey Filippov's avatar
Andrey Filippov committed
216 217 218 219
        .status           (status_data),   // input[25:0] 
        .ad               (status_ad),     // output[7:0] 
        .rq               (status_rq),     // output
        .start            (status_start)   // input
220 221 222 223 224 225
    );

fifo_same_clock   #(
    .DATA_WIDTH(CMD_WIDTH),
    .DATA_DEPTH(CMD_FIFO_DEPTH) 
    ) cmd_fifo_i (
Andrey Filippov's avatar
Andrey Filippov committed
226
        .rst       (1'b0),
227
        .clk       (mclk),
Andrey Filippov's avatar
Andrey Filippov committed
228
        .sync_rst  (chn_rst), // synchronously reset fifo;
229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246
        .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
247 248 249
    mcntrl_buf_rd #(
        .LOG2WIDTH_RD(5)
    ) chn0_buf_i (
250 251 252 253 254 255 256
        .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] 
//        .emul64       (1'b0),               // input Modify buffer addresses (used for JP4 until a 64-wide mode is implemented)
        .wclk         (!mclk),              // input
257
        .wpage_in     (page_out_r_negedge), // page_neg), // input[1:0] 
258 259 260 261 262
        .wpage_set    (page_w_set_negedge), // wpage_set_chn0_neg), // input 
        .page_next    (buf_wpage_nxt),      // input
        .page         (),                   // output[1:0]
        .we           (buf_wr),             // input
        .data_in      (buf_wdata)           // input[63:0] 
263
    );
264 265
    
// Port 1 (write DDR from AXI) buffer
266 267 268
    mcntrl_buf_wr #(
        .LOG2WIDTH_WR(5)
    ) chn1_buf_i (
269 270 271 272 273 274 275 276 277 278 279
        .ext_clk      (port1_clk),          // input
        .ext_waddr    (port1_addr),         // input[9:0] 
        .ext_we       (port1_we),           // input
        .ext_data_in  (port1_data),         // input[31:0] 
        .rclk         (mclk),               // input
        .rpage_in     (page_out_r),         // page), // input[1:0] 
        .rpage_set    (page_r_set),         // rpage_set_chn1), // input 
        .page_next    (buf_rpage_nxt),      // input
        .page         (),                   // output[1:0]
        .rd           (buf_rd),             // input
        .data_out     (buf_rdata)           // output[63:0] 
280 281 282
    );

fifo_same_clock   #(
283
    .DATA_WIDTH(3),
284 285
    .DATA_DEPTH(PAGE_FIFO_DEPTH) 
    ) page_fifo1_i (
Andrey Filippov's avatar
Andrey Filippov committed
286
        .rst       (1'b0),
287
        .clk       (mclk),                      // posedge
Andrey Filippov's avatar
Andrey Filippov committed
288
        .sync_rst  (mrst || !nreset_page_fifo), // synchronously reset fifo;
289 290
        .we        (channel_pgm_en),
        .re        (buf_run),
291
        .data_in   ({cmd_wr,cmd_page}),         // page),
292
        .data_out  ({cmd_wr_out,page_out}),
293
        .nempty    (),                          // page_fifo1_nempty),
294 295
        .half_full ()
    );
296

Andrey Filippov's avatar
Andrey Filippov committed
297 298
always @ (posedge mclk) begin
    if      (mrst)    page_out_r <= 0;
299
    else if (buf_run) page_out_r <= page_out;
300
    
301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316

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        
317
    
318 319
endmodule