dma_adapter.v 20.5 KB
Newer Older
Alexey Grebenkin's avatar
Alexey Grebenkin committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
/*******************************************************************************
 * Module: dma_adapter
 * Date: 2015-07-11  
 * Author: Alexey     
 * Description: temporary interconnect to membridge testing purposes only
 *
 * Copyright (c) 2015 Elphel, Inc.
 * dma_adapter.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.
 *
 * dma_adapter.v file 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 26 27 28 29 30 31 32
 *
 * 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"
 * files and/or simulating the code, the copyright holders of this Program give
 * 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
 * charge, and there is no dependence on any encrypted modules for simulating of
 * 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.
Alexey Grebenkin's avatar
Alexey Grebenkin committed
33 34 35 36 37 38 39 40 41 42 43 44
 *******************************************************************************/
/*
 * The module is temporary
 * It could make transactions from DMA data buffer to membridge and vice versa.
 * Processes 1 transaction of 16 x 64bit-words at a time. 
 * Waits until 1 read or 1 write is completely done.
 * After that it deasserts busy and is ready to process a new transaction.
 *
 * The whole purpose of a module as a system block is to be a buffer between 
 * a big dma data storage and axi interface. So it shall recieve data and control
 * for 1 burst and pass it to axi.
 */
Alexey Grebenkin's avatar
Alexey Grebenkin committed
45
module dma_adapter(
Alexey Grebenkin's avatar
Alexey Grebenkin committed
46 47
    input   wire                                clk,
    input   wire                                rst,
Alexey Grebenkin's avatar
Alexey Grebenkin committed
48

Alexey Grebenkin's avatar
Alexey Grebenkin committed
49 50 51 52 53 54 55 56
    // cmd iface
    input   wire                                cmd_type, // 1 = wr, 0 = rd
    input   wire                                cmd_val, // issue a cmd
    input   wire    [31:7]                      cmd_addr, // [2:0] - 64-bit (8-bytes) word offset, [6:3] - 16-words transfer offset
    output  wire                                cmd_busy, // no-pipelined cmd execution, 1 cmd at a time

    // data iface
    input   wire    [63:0]                      wr_data_in,
Alexey Grebenkin's avatar
Alexey Grebenkin committed
57 58
    input   wire                                wr_val_in,
    output  wire                                wr_ack_out,
Alexey Grebenkin's avatar
Alexey Grebenkin committed
59
    output  wire    [63:0]                      rd_data_out,
Alexey Grebenkin's avatar
Alexey Grebenkin committed
60 61
    output  wire                                rd_val_out,
    input   wire                                rd_ack_in,
Alexey Grebenkin's avatar
Alexey Grebenkin committed
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86

    // membridge iface
    output  wire    [7:0]                       cmd_ad,
    output  wire                                cmd_stb,
    input   wire    [7:0]                       status_ad,
    input   wire                                status_rq,
    output  wire                                status_start,
    input   wire                                frame_start_chn,
    input   wire                                next_page_chn,
    output  wire                                cmd_wrmem,
    output  wire                                page_ready_chn,
    output  wire                                frame_done_chn,
    output  wire    [15:0]                      line_unfinished_chn1,
    input   wire                                suspend_chn1,
    output  wire                                xfer_reset_page_rd,
    output  wire                                buf_wpage_nxt,
    output  wire                                buf_wr,
    output  wire    [63:0]                      buf_wdata,
    output  wire                                xfer_reset_page_wr,
    output  wire                                buf_rpage_nxt,
    output  wire                                buf_rd,
    input   wire    [63:0]                      buf_rdata,
    // additinal wire to indicate if membridge recieved a packet
    input   wire                                rdata_done // = membridge.is_last_in_page & membridge.afi_rready;
);
87
reg     [2:0]   membr_state;
Alexey Grebenkin's avatar
Alexey Grebenkin committed
88 89 90 91
// cmd handling
// if not busy and got cmd with val => cmd recieved, assert busy, start a respective algorithm
wire            wr_start;
wire            rd_start;
Alexey Grebenkin's avatar
Alexey Grebenkin committed
92
wire            dma_start;
Alexey Grebenkin's avatar
Alexey Grebenkin committed
93 94 95 96
reg             wr_done;
reg             rd_done;

reg             cmd_type_r;
Alexey Grebenkin's avatar
Alexey Grebenkin committed
97
reg     [31:7]  cmd_addr_r;
Alexey Grebenkin's avatar
Alexey Grebenkin committed
98 99 100 101 102
reg             cmd_busy_r;
wire            set_busy;
wire            clr_busy;

assign  set_busy = ~cmd_busy_r & cmd_val;
Alexey Grebenkin's avatar
Alexey Grebenkin committed
103 104 105 106 107
assign  clr_busy = cmd_busy_r & (wr_done | rd_done);

assign  cmd_busy = cmd_busy_r;
assign  wr_start = set_busy & cmd_type;
assign  rd_start = set_busy & ~cmd_type;
Alexey Grebenkin's avatar
Alexey Grebenkin committed
108 109 110

always @ (posedge clk)
begin
Alexey Grebenkin's avatar
Alexey Grebenkin committed
111
    cmd_type_r  <= rst ? 1'b0 : set_busy ? cmd_type : cmd_type_r;
112
    cmd_addr_r  <= rst ? 25'b0 : set_busy ? cmd_addr[31:7] : cmd_addr_r[31:7];
Alexey Grebenkin's avatar
Alexey Grebenkin committed
113
    cmd_busy_r  <= (cmd_busy_r | set_busy) & ~rst & ~clr_busy;
Alexey Grebenkin's avatar
Alexey Grebenkin committed
114 115 116
end

/*
Alexey Grebenkin's avatar
Alexey Grebenkin committed
117
 * Read/write data state machine
Alexey Grebenkin's avatar
Alexey Grebenkin committed
118 119 120 121
 * For better readability the state machine is splitted to two pieces:
 * the first one is responsible only for the CMD WRITE case handling, 
 * the second one, respectively, for CMD READ
 *
Alexey Grebenkin's avatar
Alexey Grebenkin committed
122 123
 * Simultaniously with each fsm starts a membridge fsm, which, if being 1st time launched, 
 * sets up membridge's registers, or, if have been launched before, just programs read/write 
Alexey Grebenkin's avatar
Alexey Grebenkin committed
124 125 126 127 128 129
 * address.
 *
 * Current implementation is extremely slow, but simple and reliable
 * After all other parts are implemented and this place occurs to be a bottleneck
 * then replace it (and may be membridge too) with something more ... pipelined
 */
Alexey Grebenkin's avatar
Alexey Grebenkin committed
130 131 132 133 134 135 136
// check if memberidge was already set up
reg             membr_is_set;
always @ (posedge clk)
    membr_is_set <= (membr_is_set | dma_start) & ~rst;

// common state register
reg     [3:0]   rdwr_state;
Alexey Grebenkin's avatar
Alexey Grebenkin committed
137 138

// Get data from buffer
139 140
localparam IDLE             = 0;
//localparam READ_IDLE        = 0;
Alexey Grebenkin's avatar
Alexey Grebenkin committed
141 142
localparam READ_WAIT_ADDR   = 3;
localparam READ_DATA        = 4;
143
wire            rd_reset_page;
Alexey Grebenkin's avatar
Alexey Grebenkin committed
144
reg             rd_next_page;
145
wire    [63:0]  rd_data;
Alexey Grebenkin's avatar
Alexey Grebenkin committed
146
reg     [6:0]   rd_data_count;
147
reg             rd_en;
Alexey Grebenkin's avatar
Alexey Grebenkin committed
148 149

wire            rd_stop;
150
wire    [6:0]   rd_cnt_to_pull;
Alexey Grebenkin's avatar
Alexey Grebenkin committed
151

152
assign  rd_cnt_to_pull = 7'hf;
Alexey Grebenkin's avatar
Alexey Grebenkin committed
153 154
assign  rd_stop = rd_ack_in & rd_data_count == rd_cnt_to_pull;

155 156 157
assign  rd_reset_page = 1'b0;
assign  rd_data     = buf_rdata;
assign  rd_val_out  = rd_en;
Alexey Grebenkin's avatar
Alexey Grebenkin committed
158
assign  rd_data_out = rd_data;
Alexey Grebenkin's avatar
Alexey Grebenkin committed
159

160
/*always @ (posedge clk)
Alexey Grebenkin's avatar
Alexey Grebenkin committed
161 162
    if (rst)
    begin
Alexey Grebenkin's avatar
Alexey Grebenkin committed
163 164 165 166 167
        rdwr_state      <= READ_IDLE;
        rd_done         <= 1'b0;
        rd_data_count   <= 7'h0;
        rd_next_page    <= 1'b0;
        rd_en           <= 1'b0;
Alexey Grebenkin's avatar
Alexey Grebenkin committed
168 169
    end
    else
170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203
        case (rdwr_state)
            READ_IDLE:
            begin
                rdwr_state      <= rd_start ? READ_WAIT_ADDR : READ_IDLE;
                rd_done         <= 1'b0;
                rd_data_count   <= 7'h0;
                rd_next_page    <= 1'b0;
                rd_en           <= 1'b0;
            end
            READ_WAIT_ADDR: // wait until address information is sent to the bus and input buffer got data
            begin
                rdwr_state      <= membr_state == READ_IDLE & rdata_done ? READ_DATA : READ_WAIT_ADDR;
                rd_done         <= 1'b0;
                rd_data_count   <= 7'h0;
                rd_next_page    <= 1'b0;
                rd_en           <= 1'b0;
            end
            READ_DATA: 
            begin
                rdwr_state      <= rd_stop ? READ_IDLE : READ_DATA;
                rd_done         <= rd_stop ? 1'b1 : 1'b0;
                rd_data_count   <= rd_ack_in ? rd_data_count + 1'b1 : rd_data_count;
                rd_next_page    <= rd_stop ? 1'b1 : 1'b0;
                rd_en           <= rd_ack_in ? 1'b1 : 1'b0;
            end
            default: // write is processing
            begin
                rdwr_state      <= READ_IDLE;
                rd_done         <= 1'b0;
                rd_data_count   <= 7'h0;
                rd_next_page    <= 1'b0;
                rd_en           <= 1'b0;
            end
        endcase
204
*/
Alexey Grebenkin's avatar
Alexey Grebenkin committed
205 206

// Put data into buffer
207
//localparam WRITE_IDLE       = 0;
Alexey Grebenkin's avatar
Alexey Grebenkin committed
208 209
localparam WRITE_DATA       = 1;
localparam WRITE_WAIT_ADDR  = 2;
Alexey Grebenkin's avatar
Alexey Grebenkin committed
210 211 212 213
reg             wr_en;
reg             wr_reset_page;
reg             wr_next_page;
reg     [63:0]  wr_data;
Alexey Grebenkin's avatar
Alexey Grebenkin committed
214
reg     [6:0]   wr_data_count;
Alexey Grebenkin's avatar
Alexey Grebenkin committed
215 216 217 218 219 220 221
reg             wr_page_ready;
reg             wr_val;

wire    [6:0]   wr_cnt_to_push;
wire            wr_stop;

assign  wr_cnt_to_push  = 7'hf;
Alexey Grebenkin's avatar
Alexey Grebenkin committed
222
assign  wr_stop         = wr_val_in & wr_data_count == wr_cnt_to_push;
Alexey Grebenkin's avatar
Alexey Grebenkin committed
223

Alexey Grebenkin's avatar
Alexey Grebenkin committed
224
assign  wr_ack_out   = wr_val_in & rdwr_state == WRITE_DATA;
Alexey Grebenkin's avatar
Alexey Grebenkin committed
225
//assign  wr_data_in   = wr_data;
Alexey Grebenkin's avatar
Alexey Grebenkin committed
226 227 228 229 230 231


// assuming for now we write only pre-defined 16 64-bit words
always @ (posedge clk)
    if (rst)
    begin
232 233 234 235 236
        rdwr_state      <= IDLE;
        rd_done         <= 1'b0;
        rd_data_count   <= 7'h0;
        rd_next_page    <= 1'b0;
        rd_en           <= 1'b0;
Alexey Grebenkin's avatar
Alexey Grebenkin committed
237
        wr_done         <= 1'b0;
Alexey Grebenkin's avatar
Alexey Grebenkin committed
238
        wr_data_count   <= 7'd0;
Alexey Grebenkin's avatar
Alexey Grebenkin committed
239 240 241 242 243 244 245 246
        wr_val          <= 1'b0;
        wr_data         <= 64'h0;
        wr_next_page    <= 1'b0;
        wr_reset_page   <= 1'b0;
        wr_en           <= 1'b0;
        wr_page_ready   <= 1'b0;
    end
    else
247
        case (rdwr_state)
248
            IDLE:
Alexey Grebenkin's avatar
Alexey Grebenkin committed
249
            begin
250 251 252 253 254
                rdwr_state      <= rd_start ? READ_WAIT_ADDR : wr_start ? WRITE_DATA : IDLE;
                rd_done         <= 1'b0;
                rd_data_count   <= 7'h0;
                rd_next_page    <= 1'b0;
                rd_en           <= 1'b0;
Alexey Grebenkin's avatar
Alexey Grebenkin committed
255
                wr_data_count   <= 7'd0;
Alexey Grebenkin's avatar
Alexey Grebenkin committed
256 257 258 259 260 261 262
                wr_done         <= 1'b0;
                wr_data         <= 64'h0;
                wr_next_page    <= 1'b0;
                wr_reset_page   <= wr_start ? 1'b1 : 1'b0;
                wr_en           <= 1'b0;
                wr_page_ready   <= 1'b0;
            end
Alexey Grebenkin's avatar
Alexey Grebenkin committed
263
            WRITE_DATA:
Alexey Grebenkin's avatar
Alexey Grebenkin committed
264
            begin
265
                wr_done         <= wr_stop & membr_state == IDLE ? 1'b1 : 1'b0;
Alexey Grebenkin's avatar
Alexey Grebenkin committed
266
                wr_data_count   <= wr_val_in ? wr_data_count + 1'b1 : wr_data_count;
267
                wr_data         <= wr_data_in;
Alexey Grebenkin's avatar
Alexey Grebenkin committed
268 269
                wr_next_page    <= wr_stop ? 1'b1 : 1'b0;
                wr_reset_page   <= 1'b0;
Alexey Grebenkin's avatar
Alexey Grebenkin committed
270
                wr_en           <= wr_val_in;
Alexey Grebenkin's avatar
Alexey Grebenkin committed
271
                wr_page_ready   <= wr_stop ? 1'b1 : 1'b0;
272
                rdwr_state      <= wr_stop & membr_state == IDLE ? IDLE : 
Alexey Grebenkin's avatar
Alexey Grebenkin committed
273
                                   wr_stop                       ? WRITE_WAIT_ADDR : WRITE_DATA;
274 275 276 277
                rd_done         <= 1'b0;
                rd_data_count   <= 7'h0;
                rd_next_page    <= 1'b0;
                rd_en           <= 1'b0;
Alexey Grebenkin's avatar
Alexey Grebenkin committed
278 279 280
            end
            WRITE_WAIT_ADDR: // in case all data is written into a buffer, but address is still being issued on axi bus
            begin
281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316
                wr_done         <= membr_state == IDLE ? 1'b1 : 1'b0;
                wr_data_count   <= 7'd0;
                wr_data         <= 64'h0;
                wr_next_page    <= 1'b0;
                wr_reset_page   <= 1'b0;
                wr_en           <= 1'b0;
                wr_page_ready   <= 1'b0;
                rdwr_state      <= membr_state == IDLE ? IDLE : WRITE_WAIT_ADDR;
                rd_done         <= 1'b0;
                rd_data_count   <= 7'h0;
                rd_next_page    <= 1'b0;
                rd_en           <= 1'b0;
            end
            READ_WAIT_ADDR: // wait until address information is sent to the bus and input buffer got data
            begin
                rdwr_state      <= membr_state == IDLE & rdata_done ? READ_DATA : READ_WAIT_ADDR;
                rd_done         <= 1'b0;
                rd_data_count   <= 7'h0;
                rd_next_page    <= 1'b0;
                rd_en           <= 1'b0;
                wr_done         <= 1'b0;
                wr_data_count   <= 7'd0;
                wr_data         <= 64'h0;
                wr_next_page    <= 1'b0;
                wr_reset_page   <= 1'b0;
                wr_en           <= 1'b0;
                wr_page_ready   <= 1'b0;
            end
            READ_DATA: 
            begin
                rdwr_state      <= rd_stop ? IDLE : READ_DATA;
                rd_done         <= rd_stop ? 1'b1 : 1'b0;
                rd_data_count   <= rd_ack_in ? rd_data_count + 1'b1 : rd_data_count;
                rd_next_page    <= rd_stop ? 1'b1 : 1'b0;
                rd_en           <= rd_ack_in ? 1'b1 : 1'b0;
                wr_done         <= 1'b0;
Alexey Grebenkin's avatar
Alexey Grebenkin committed
317 318 319 320 321 322
                wr_data_count   <= 7'd0;
                wr_data         <= 64'h0;
                wr_next_page    <= 1'b0;
                wr_reset_page   <= 1'b0;
                wr_en           <= 1'b0;
                wr_page_ready   <= 1'b0;
Alexey Grebenkin's avatar
Alexey Grebenkin committed
323 324 325 326
            end
            default: // read is executed
            begin
                wr_done         <= 1'b0;
Alexey Grebenkin's avatar
Alexey Grebenkin committed
327
                wr_data_count   <= 7'd0;
Alexey Grebenkin's avatar
Alexey Grebenkin committed
328 329 330 331 332
                wr_data         <= 64'h0;
                wr_next_page    <= 1'b0;
                wr_reset_page   <= 1'b0;
                wr_en           <= 1'b0;
                wr_page_ready   <= 1'b0;
333 334 335 336 337
                rdwr_state      <= IDLE;
                rd_done         <= 1'b0;
                rd_data_count   <= 7'h0;
                rd_next_page    <= 1'b0;
                rd_en           <= 1'b0;
Alexey Grebenkin's avatar
Alexey Grebenkin committed
338 339 340
            end
        endcase

Alexey Grebenkin's avatar
Alexey Grebenkin committed
341 342 343 344 345 346
// membridge interface assigments
assign  status_start        = 1'b0; // no need until status is used
assign  cmd_wrmem           = ~cmd_type_r;
assign  xfer_reset_page_wr  = rd_reset_page;
assign  buf_rpage_nxt       = rd_next_page;
assign  buf_rd              = rd_en;
Alexey Grebenkin's avatar
Alexey Grebenkin committed
347 348 349 350 351 352 353
assign  buf_wdata           = wr_data;
assign  buf_wr              = wr_en;
assign  buf_wpage_nxt       = wr_next_page;
assign  xfer_reset_page_rd  = wr_reset_page;
assign  page_ready_chn      = cmd_wrmem ? 1'b0 : wr_page_ready;
assign  frame_done_chn      = 1'b1;

Alexey Grebenkin's avatar
Alexey Grebenkin committed
354 355 356
/*
 * Transfer address and membridge set-ups state machine
 */
Alexey Grebenkin's avatar
Alexey Grebenkin committed
357 358 359 360 361 362 363 364 365
localparam MEMBR_IDLE   = 0;
localparam MEMBR_MODE   = 1;
localparam MEMBR_WIDTH  = 2;
localparam MEMBR_LEN    = 3;
localparam MEMBR_START  = 4;
localparam MEMBR_SIZE   = 5;
localparam MEMBR_LOADDR = 6;
localparam MEMBR_CTRL   = 7;

366
reg     [31:0]  membr_data;
Alexey Grebenkin's avatar
Alexey Grebenkin committed
367 368 369 370 371 372
reg     [15:0]  membr_addr;
reg             membr_start;
reg             membr_done;
reg             membr_setup; // indicates the first tick of the state
wire            membr_inprocess;

Alexey Grebenkin's avatar
Alexey Grebenkin committed
373
assign  dma_start = wr_start | rd_start;
Alexey Grebenkin's avatar
Alexey Grebenkin committed
374 375 376 377 378 379 380 381

always @ (posedge clk)
    if (rst)
    begin
        membr_data  <= 32'h0;
        membr_addr  <= 16'h0;
        membr_start <= 1'b0;
        membr_setup <= 1'b0;
Alexey Grebenkin's avatar
Alexey Grebenkin committed
382
        membr_done  <= 1'b0;
Alexey Grebenkin's avatar
Alexey Grebenkin committed
383 384 385 386 387 388 389 390 391 392
        membr_state <= MEMBR_IDLE;
    end
    else
        case (membr_state)
            MEMBR_IDLE:
            begin
                membr_data  <= 32'h0;
                membr_addr  <= 16'h200;
                membr_start <= dma_start ? 1'b1 : 1'b0;
                membr_setup <= dma_start ? 1'b1 : 1'b0;
Alexey Grebenkin's avatar
Alexey Grebenkin committed
393
                membr_done  <= 1'b0;
394
                membr_state <= dma_start &  membr_is_set ? MEMBR_LOADDR : 
Alexey Grebenkin's avatar
Alexey Grebenkin committed
395
                               dma_start                 ? MEMBR_MODE : MEMBR_IDLE;
Alexey Grebenkin's avatar
Alexey Grebenkin committed
396 397 398 399 400 401 402
            end
            MEMBR_MODE:
            begin
                membr_data  <= 32'h3;
                membr_addr  <= 16'h207;
                membr_start <= membr_inprocess ? 1'b0 : 1'b1;
                membr_setup <= membr_inprocess | membr_setup ? 1'b0 : 1'b1;
Alexey Grebenkin's avatar
Alexey Grebenkin committed
403
                membr_done  <= 1'b0;
Alexey Grebenkin's avatar
Alexey Grebenkin committed
404 405 406 407 408 409 410 411
                membr_state <= membr_inprocess | membr_setup ? MEMBR_MODE : MEMBR_WIDTH;
            end
            MEMBR_WIDTH:
            begin
                membr_data  <= 32'h10;
                membr_addr  <= 16'h206;
                membr_start <= membr_inprocess ? 1'b0 : 1'b1;
                membr_setup <= membr_inprocess | membr_setup ? 1'b0 : 1'b1;
Alexey Grebenkin's avatar
Alexey Grebenkin committed
412
                membr_done  <= 1'b0;
Alexey Grebenkin's avatar
Alexey Grebenkin committed
413 414 415 416 417 418 419 420
                membr_state <= membr_inprocess | membr_setup ? MEMBR_WIDTH : MEMBR_LEN;
            end
            MEMBR_LEN:
            begin
                membr_data  <= 32'h10;
                membr_addr  <= 16'h205;
                membr_start <= membr_inprocess ? 1'b0 : 1'b1;
                membr_setup <= membr_inprocess | membr_setup ? 1'b0 : 1'b1;
Alexey Grebenkin's avatar
Alexey Grebenkin committed
421
                membr_done  <= 1'b0;
Alexey Grebenkin's avatar
Alexey Grebenkin committed
422 423 424 425 426 427 428 429
                membr_state <= membr_inprocess | membr_setup ? MEMBR_LEN : MEMBR_START;
            end
            MEMBR_START:
            begin
                membr_data  <= 32'h0;
                membr_addr  <= 16'h204;
                membr_start <= membr_inprocess ? 1'b0 : 1'b1;
                membr_setup <= membr_inprocess | membr_setup ? 1'b0 : 1'b1;
Alexey Grebenkin's avatar
Alexey Grebenkin committed
430
                membr_done  <= 1'b0;
Alexey Grebenkin's avatar
Alexey Grebenkin committed
431 432 433 434 435 436 437 438
                membr_state <= membr_inprocess | membr_setup ? MEMBR_START : MEMBR_SIZE;
            end
            MEMBR_SIZE:
            begin
                membr_data  <= 32'h10;
                membr_addr  <= 16'h203;
                membr_start <= membr_inprocess ? 1'b0 : 1'b1;
                membr_setup <= membr_inprocess | membr_setup ? 1'b0 : 1'b1;
Alexey Grebenkin's avatar
Alexey Grebenkin committed
439
                membr_done  <= 1'b0;
Alexey Grebenkin's avatar
Alexey Grebenkin committed
440 441 442 443
                membr_state <= membr_inprocess | membr_setup ? MEMBR_SIZE : MEMBR_LOADDR;
            end
            MEMBR_LOADDR:
            begin
444
                membr_data  <= {7'h0, cmd_addr_r[31:7]};
Alexey Grebenkin's avatar
Alexey Grebenkin committed
445 446 447
                membr_addr  <= 16'h202;
                membr_start <= membr_inprocess ? 1'b0 : 1'b1;
                membr_setup <= membr_inprocess | membr_setup ? 1'b0 : 1'b1;
Alexey Grebenkin's avatar
Alexey Grebenkin committed
448
                membr_done  <= 1'b0;
Alexey Grebenkin's avatar
Alexey Grebenkin committed
449 450 451 452 453 454 455 456
                membr_state <= membr_inprocess | membr_setup ? MEMBR_LOADDR : MEMBR_CTRL;
            end
            MEMBR_CTRL:
            begin
                membr_data  <= {28'h0000000, 4'b0011};
                membr_addr  <= 16'h200;
                membr_start <= membr_inprocess ? 1'b0 : 1'b1;
                membr_setup <= 1'b0;
Alexey Grebenkin's avatar
Alexey Grebenkin committed
457
                membr_done  <= membr_inprocess | membr_setup ? 1'b0 : 1'b1;
Alexey Grebenkin's avatar
Alexey Grebenkin committed
458 459 460 461 462 463 464 465
                membr_state <= membr_inprocess | membr_setup ? MEMBR_CTRL : MEMBR_IDLE;
            end
            default:
            begin
                membr_data  <= 32'h0;
                membr_addr  <= 16'h0;
                membr_start <= 1'b0;
                membr_setup <= 1'b0;
Alexey Grebenkin's avatar
Alexey Grebenkin committed
466
                membr_done  <= 1'b0;
Alexey Grebenkin's avatar
Alexey Grebenkin committed
467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547
                membr_state <= MEMBR_IDLE;
            end
        endcase

// write to memridge registers fsm
localparam STATE_IDLE   = 3'h0;
localparam STATE_CMD_0  = 3'h1;
localparam STATE_CMD_1  = 3'h2;
localparam STATE_DATA_0 = 3'h3;
localparam STATE_DATA_1 = 3'h4;
localparam STATE_DATA_2 = 3'h5;
localparam STATE_DATA_3 = 3'h6;

reg     [2:0]   state;
reg     [7:0]   out_ad;
reg             out_stb;

assign  membr_inprocess = state != STATE_IDLE;
assign  cmd_ad          = out_ad;
assign  cmd_stb         = out_stb;

always @ (posedge clk)
    if (rst)
    begin
        state   <= STATE_IDLE;
        out_ad  <= 8'h0;
        out_stb <= 1'b0;
    end
    else
        case (state)
            STATE_IDLE: 
            begin
                out_ad  <= 8'h0;
                out_stb <= 1'b0;
                state   <= membr_setup ? STATE_CMD_0 : STATE_IDLE;
            end
            STATE_CMD_0:
            begin
                out_ad  <= membr_addr[7:0];
                out_stb <= 1'b1;
                state   <= STATE_CMD_1;
            end
            STATE_CMD_1:
            begin
                out_ad  <= membr_addr[15:8];
                out_stb <= 1'b0;
                state   <= STATE_DATA_0;
            end
            STATE_DATA_0:
            begin
                out_ad  <= membr_data[7:0];
                out_stb <= 1'b0;
                state   <= STATE_DATA_1;
            end
            STATE_DATA_1:
            begin
                out_ad  <= membr_data[15:8];
                out_stb <= 1'b0;
                state   <= STATE_DATA_2;
            end
            STATE_DATA_2:
            begin
                out_ad  <= membr_data[23:16];
                out_stb <= 1'b0;
                state   <= STATE_DATA_3;
            end
            STATE_DATA_3:
            begin
                out_ad  <= membr_data[31:24];
                out_stb <= 1'b0;
                state   <= STATE_IDLE;
            end
            default:
            begin
                out_ad  <= 8'hff;
                out_stb <= 1'b0;
                state   <= STATE_IDLE;
            end
        endcase

endmodule