mcntrl_ps_pio.v 13 KB
Newer Older
1 2 3 4 5 6 7
/*!
 * <b>Module:</b>mcntrl_ps_pio
 * @file mcntrl_ps_pio.v
 * @date 2015-01-27  
 * @author Andrey Filippov     
 *
 * @brief Read/write channels to DDR3 memory with software-programmable
8 9
 * command sequence
 *
10 11 12 13
 * @copyright Copyright (c) 2015 Elphel, Inc.
 *
 * <b>License:</b>
 *
14 15 16 17 18 19 20 21 22 23 24 25
 * 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/> .
26 27 28 29 30 31
 *
 * 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"
32
 * files and/or simulating the code, the copyright holders of this Program give
33 34
 * 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
35
 * charge, and there is no dependence on any encrypted modules for simulating of
36 37 38
 * 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.
39
 */
40
`timescale 1ns/1ps
41
`include "system_defines.vh" 
Andrey Filippov's avatar
Andrey Filippov committed
42
`undef DEBUG_FIFO
43
module  mcntrl_ps_pio#(
44 45 46
    parameter MCNTRL_PS_ADDR=                    'h100,
    parameter MCNTRL_PS_MASK=                    'h3e0, // both channels 0 and 1
    parameter MCNTRL_PS_STATUS_REG_ADDR=         'h2,
47 48 49 50
    parameter MCNTRL_PS_EN_RST=                  'h0,
    parameter MCNTRL_PS_CMD=                     'h1,
    parameter MCNTRL_PS_STATUS_CNTRL=            'h2
)(
Andrey Filippov's avatar
Andrey Filippov committed
51
    input                        mrst,
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
    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   
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
    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 
90
);
91
 localparam CMD_WIDTH=15;
92
 localparam CMD_FIFO_DEPTH=4;
93 94 95 96
 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; 
97

Andrey Filippov's avatar
Andrey Filippov committed
98 99

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

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;



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

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

fifo_same_clock   #(
    .DATA_WIDTH(CMD_WIDTH),
    .DATA_DEPTH(CMD_FIFO_DEPTH) 
    ) cmd_fifo_i (
Andrey Filippov's avatar
Andrey Filippov committed
231
        .rst       (1'b0),
232
        .clk       (mclk),
Andrey Filippov's avatar
Andrey Filippov committed
233
        .sync_rst  (chn_rst), // synchronously reset fifo;
234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251
        .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
252 253 254
    mcntrl_buf_rd #(
        .LOG2WIDTH_RD(5)
    ) chn0_buf_i (
255 256 257 258 259 260 261
        .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
262
        .wpage_in     (page_out_r_negedge), // page_neg), // input[1:0] 
263 264 265 266 267
        .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] 
268
    );
269 270
    
// Port 1 (write DDR from AXI) buffer
271 272 273
    mcntrl_buf_wr #(
        .LOG2WIDTH_WR(5)
    ) chn1_buf_i (
274 275 276 277 278 279 280 281 282 283 284
        .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] 
285 286 287
    );

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

Andrey Filippov's avatar
Andrey Filippov committed
302 303
always @ (posedge mclk) begin
    if      (mrst)    page_out_r <= 0;
304
    else if (buf_run) page_out_r <= page_out;
305
    
306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321

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        
322
    
323 324
endmodule