Commit 869188e9 authored by Alexey Grebenkin's avatar Alexey Grebenkin
Browse files

dma_adapter rtl done

parent 6a13fd70
Loading
Loading
Loading
Loading
+121 −94
Original line number Diff line number Diff line
@@ -29,26 +29,13 @@
 * a big dma data storage and axi interface. So it shall recieve data and control
 * for 1 burst and pass it to axi.
 */
/*
 * For debug only:
 * DMA write:
 * 0x0c: |mem[:] => use dbg registers as a source of dma data
 * 0x10: addr of the buffer
 * 0x14: size
 * 0x18: burst len
 * 0x1c: start dma
 * 0x20-0x3c - data
 */
module send_dma #(
    parameter   REGISTERS_CNT = 20
)
(
    input   wire                                clk,
    input   wire                                rst,
    // dbg iface
    input   wire    [32*REGISTERS_CNT - 1:0]    mem,
    input   wire                                dbg_mode,
    output  wire                                clrstart,

    // cmd iface
    input   wire                                cmd_type, // 1 = wr, 0 = rd
    input   wire                                cmd_val, // issue a cmd
@@ -57,9 +44,11 @@ module send_dma #(

    // data iface
    input   wire    [63:0]                      wr_data_in,
    output  wire                                wr_val_out,
    input   wire                                wr_val_in,
    output  wire                                wr_ack_out,
    output  wire    [63:0]                      rd_data_out,
    input   wire                                rd_val_in,
    output  wire                                rd_val_out,
    input   wire                                rd_ack_in,

    // membridge iface
    output  wire    [7:0]                       cmd_ad,
@@ -89,91 +78,133 @@ module send_dma #(
// if not busy and got cmd with val => cmd recieved, assert busy, start a respective algorithm
wire            wr_start;
wire            rd_start;
wire            dma_start;
reg             wr_done;
reg             rd_done;

reg             cmd_type_r;
reg             cmd_addr_r;
reg             cmd_val_r;
reg     [31:7]  cmd_addr_r;
reg             cmd_busy_r;
wire            set_busy;
wire            clr_busy;

assign  set_busy = ~cmd_busy_r & cmd_val;
assign  clr_busy = cmd_busy_r & (wr_done | rd_done)
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;

always @ (posedge clk)
begin
    cmd_type_r  <= rst ? 1'b0 : 
    cmd_addr_r  <= rst ? 1'b0 :
    cmd_val_r   <= rst ? 1'b0 :
    cmd_busy_r  <= rst ? 1'b0 : ~cmd_busy_r & cmd_val_r
    cmd_type_r  <= rst ? 1'b0 : set_busy ? cmd_type : cmd_type_r;
    cmd_addr_r  <= rst ? 1'b0 : set_busy ? cmd_addr : cmd_addr_r;
    cmd_busy_r  <= (cmd_busy_r | set_busy) & ~rst & ~clr_busy;
end

/*
 * Read/write state machine
 * Read/write data state machine
 * 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
 *
 * 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 
 * 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 
 * 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
 */
reg     [1:0]   rdwr_state;
// 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;

// Get data from buffer
localparam READ_IDLE        = 0;
localparam READ_ON      = 2;
localparam READ_DATA    = 3;
localparam READ_WAIT_ADDR   = 3;
localparam READ_DATA        = 4;
reg             rd_reset_page;
reg             rd_next_page;
reg             rd_data
reg             rd_data;
reg     [6:0]   rd_data_count;

wire            rd_stop;
wire            rd_cnt_to_pull;

assign  rd_cnt_to_pull == 7'hf;
assign  rd_stop = rd_ack_in & rd_data_count == rd_cnt_to_pull;

assign  rd_data_out = rd_data;

always @ (posedge clk)
    if (rst)
    begin
        rd_state    <= READ_IDLE;
        rd_done     <= 

        rdwr_state      <= READ_IDLE;
        rd_done         <= 1'b0;
        rd_data_count   <= 7'h0;
        rd_next_page    <= 1'b0;
        rd_en           <= 1'b0;
    end
    else
        case (rst)
        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_ON:
        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;
        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


// Put data into buffer
localparam WRITE_IDLE       = 0;
localparam WRITE_ON     = 1;
localparam WRITE_DATA       = 1;
localparam WRITE_WAIT_ADDR  = 2;
reg             wr_en;
reg             wr_reset_page;
reg             wr_next_page;
reg     [63:0]  wr_data;
reg     [6:0]   wr_page_offset;
reg     [6:0]   wr_data_count;
reg             wr_page_ready;
reg             wr_val;

wire    [31:0]  dw0 = mem[32*9-1:32*8];
wire    [31:0]  dw1 = mem[32*10-1:32*9];
wire    [31:0]  dw2 = mem[32*11-1:32*10];
wire    [31:0]  dw3 = mem[32*12-1:32*11];

wire    [6:0]   wr_cnt_to_push;
wire            wr_stop;

assign  wr_cnt_to_push  = 7'hf;
assign  wr_stop         = wr_page_offset == wr_cnt_to_push;
assign  wr_stop         = wr_val_in & wr_data_count == wr_cnt_to_push;

assign  wr_val_in    = wr_val;
assign  wr_ack_out   = wr_val_in & rdwr_state == WRITE_DATA;
assign  wr_data_in   = wr_data;


@@ -182,7 +213,7 @@ always @ (posedge clk)
    if (rst)
    begin
        wr_done         <= 1'b0;
        wr_page_offset  <= 7'd0;
        wr_data_count   <= 7'd0;
        wr_val          <= 1'b0;
        wr_data         <= 64'h0;
        wr_next_page    <= 1'b0;
@@ -195,37 +226,42 @@ always @ (posedge clk)
        case (wr_state)
            WRITE_IDLE:
            begin
                wr_page_offset  <= 7'd0;
                wr_data_count   <= 7'd0;
                wr_done         <= 1'b0;
                wr_val          <= 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;
                rdwr_state      <= wr_start ? WRITE_ON : WRITE_IDLE;
                rdwr_state      <= wr_start ? WRITE_DATA : WRITE_IDLE;
            end
            WRITE_ON:
            WRITE_DATA:
            begin
                wr_done         <= wr_stop ? 1'b1 : 1'b0;
                wr_page_offset  <= wr_page_offset + 1'b1;
                wr_val          <= 1'b1;
                wr_data         <= ~dbg_mode ? in_data : 
                                   wr_page_offset[1:0] == 2'b00 ? {dw0, 25'h0, wr_page_offset} :
                                   wr_page_offset[1:0] == 2'b01 ? {dw1, 25'h0, wr_page_offset} : 
                                   wr_page_offset[1:0] == 2'b10 ? {dw2, 25'h0, wr_page_offset} :
                                                                  {dw3, 25'h0, wr_page_offset};
                wr_done         <= wr_stop & membr_state == IDLE ? 1'b1 : 1'b0;
                wr_data_count   <= wr_val_in ? wr_data_count + 1'b1 : wr_data_count;
                wr_data         <= in_data : 
                wr_next_page    <= wr_stop ? 1'b1 : 1'b0;
                wr_reset_page   <= 1'b0;
                wr_en           <= 1'b1;
                wr_en           <= wr_val_in;
                wr_page_ready   <= wr_stop ? 1'b1 : 1'b0;
                rdwr_state      <= wr_stop ? WRITE_IDLE : WRITE_ON;
                rdwr_state      <= wr_stop & membr_state == IDLE ? WRITE_IDLE : 
                                   wr_stop                       ? WRITE_WAIT_ADDR : WRITE_DATA;
            end
            WRITE_WAIT_ADDR: // in case all data is written into a buffer, but address is still being issued on axi bus
            begin
                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 ? WRITE_IDLE : WRITE_WAIT_ADDR;
            end
            default: // read is executed
            begin
                wr_done         <= 1'b0;
                wr_page_offset  <= 7'd0;
                wr_val          <= 1'b0;
                wr_data_count   <= 7'd0;
                wr_data         <= 64'h0;
                wr_next_page    <= 1'b0;
                wr_reset_page   <= 1'b0;
@@ -235,13 +271,12 @@ always @ (posedge clk)
            end
        endcase

// temporary assigments
// membridge interface assigments
assign  status_start        = 1'b0; // no need until status is used
assign  cmd_wrmem       = 1'b0; // for now only writing
assign  xfer_reset_page_wr  = 1'b0; // for now only writing
assign  buf_rpage_nxt       = 1'b0; // for now only writing
assign  buf_rd              = 1'b0; // for now only writing
assign  xfer_reset_page_wr  = 1'b0; 
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;
assign  buf_wdata           = wr_data;
assign  buf_wr              = wr_en;
assign  buf_wpage_nxt       = wr_next_page;
@@ -249,16 +284,9 @@ 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;


// compute membridge parameters to corresponding mem register
// dma fsm
// mode = 0
// width = 4
// size = 0x14
// start = 0
// lo_address = 0x10
// ctrl = 0x1c
// len = 0x18
/*
 * Transfer address and membridge set-ups state machine
 */
localparam MEMBR_IDLE   = 0;
localparam MEMBR_MODE   = 1;
localparam MEMBR_WIDTH  = 2;
@@ -275,11 +303,8 @@ reg membr_done;
reg     [2:0]   membr_state;
reg             membr_setup; // indicates the first tick of the state
wire            membr_inprocess;
wire            dma_start;

assign  dma_start = |mem[32*8-1:32*7];
assign  clrstart = dma_start & membr_state == MEMBR_IDLE;
//assign  wr_start = membr_state == MEMBR_CTRL;
assign  dma_start = wr_start | rd_start;

always @ (posedge clk)
    if (rst)
@@ -288,6 +313,7 @@ always @ (posedge clk)
        membr_addr  <= 16'h0;
        membr_start <= 1'b0;
        membr_setup <= 1'b0;
        membr_done  <= 1'b0;
        membr_state <= MEMBR_IDLE;
    end
    else
@@ -298,7 +324,9 @@ always @ (posedge clk)
                membr_addr  <= 16'h200;
                membr_start <= dma_start ? 1'b1 : 1'b0;
                membr_setup <= dma_start ? 1'b1 : 1'b0;
                membr_state <= dma_start ? MEMBR_MODE : MEMBR_IDLE;
                membr_done  <= 1'b0;
                membr_state <= dma_start &  membr_is_set ? MEMBR_LOADDDR : 
                               dma_start                 ? MEMBR_MODE : MEMBR_IDLE;
            end
            MEMBR_MODE:
            begin
@@ -306,6 +334,7 @@ always @ (posedge clk)
                membr_addr  <= 16'h207;
                membr_start <= membr_inprocess ? 1'b0 : 1'b1;
                membr_setup <= membr_inprocess | membr_setup ? 1'b0 : 1'b1;
                membr_done  <= 1'b0;
                membr_state <= membr_inprocess | membr_setup ? MEMBR_MODE : MEMBR_WIDTH;
            end
            MEMBR_WIDTH:
@@ -314,6 +343,7 @@ always @ (posedge clk)
                membr_addr  <= 16'h206;
                membr_start <= membr_inprocess ? 1'b0 : 1'b1;
                membr_setup <= membr_inprocess | membr_setup ? 1'b0 : 1'b1;
                membr_done  <= 1'b0;
                membr_state <= membr_inprocess | membr_setup ? MEMBR_WIDTH : MEMBR_LEN;
            end
            MEMBR_LEN:
@@ -322,6 +352,7 @@ always @ (posedge clk)
                membr_addr  <= 16'h205;
                membr_start <= membr_inprocess ? 1'b0 : 1'b1;
                membr_setup <= membr_inprocess | membr_setup ? 1'b0 : 1'b1;
                membr_done  <= 1'b0;
                membr_state <= membr_inprocess | membr_setup ? MEMBR_LEN : MEMBR_START;
            end
            MEMBR_START:
@@ -330,6 +361,7 @@ always @ (posedge clk)
                membr_addr  <= 16'h204;
                membr_start <= membr_inprocess ? 1'b0 : 1'b1;
                membr_setup <= membr_inprocess | membr_setup ? 1'b0 : 1'b1;
                membr_done  <= 1'b0;
                membr_state <= membr_inprocess | membr_setup ? MEMBR_START : MEMBR_SIZE;
            end
            MEMBR_SIZE:
@@ -338,14 +370,16 @@ always @ (posedge clk)
                membr_addr  <= 16'h203;
                membr_start <= membr_inprocess ? 1'b0 : 1'b1;
                membr_setup <= membr_inprocess | membr_setup ? 1'b0 : 1'b1;
                membr_done  <= 1'b0;
                membr_state <= membr_inprocess | membr_setup ? MEMBR_SIZE : MEMBR_LOADDR;
            end
            MEMBR_LOADDR:
            begin
                membr_data  <= mem[32*5-1:32*4];
                membr_data  <= cmd_addr_r;
                membr_addr  <= 16'h202;
                membr_start <= membr_inprocess ? 1'b0 : 1'b1;
                membr_setup <= membr_inprocess | membr_setup ? 1'b0 : 1'b1;
                membr_done  <= 1'b0;
                membr_state <= membr_inprocess | membr_setup ? MEMBR_LOADDR : MEMBR_CTRL;
            end
            MEMBR_CTRL:
@@ -354,6 +388,7 @@ always @ (posedge clk)
                membr_addr  <= 16'h200;
                membr_start <= membr_inprocess ? 1'b0 : 1'b1;
                membr_setup <= 1'b0;
                membr_done  <= membr_inprocess | membr_setup ? 1'b0 : 1'b1;
                membr_state <= membr_inprocess | membr_setup ? MEMBR_CTRL : MEMBR_IDLE;
            end
            default:
@@ -362,6 +397,7 @@ always @ (posedge clk)
                membr_addr  <= 16'h0;
                membr_start <= 1'b0;
                membr_setup <= 1'b0;
                membr_done  <= 1'b0;
                membr_state <= MEMBR_IDLE;
            end
        endcase
@@ -386,7 +422,6 @@ assign cmd_stb = out_stb;
always @ (posedge clk)
    if (rst)
    begin
        membr_done  <= 1'b0;
        state   <= STATE_IDLE;
        out_ad  <= 8'h0;
        out_stb <= 1'b0;
@@ -395,56 +430,48 @@ always @ (posedge clk)
        case (state)
            STATE_IDLE: 
            begin
                membr_done  <= 1'b0;
                out_ad  <= 8'h0;
                out_stb <= 1'b0;
                state   <= membr_setup ? STATE_CMD_0 : STATE_IDLE;
            end
            STATE_CMD_0:
            begin
                membr_done  <= 1'b0;
                out_ad  <= membr_addr[7:0];
                out_stb <= 1'b1;
                state   <= STATE_CMD_1;
            end
            STATE_CMD_1:
            begin
                membr_done  <= 1'b0;
                out_ad  <= membr_addr[15:8];
                out_stb <= 1'b0;
                state   <= STATE_DATA_0;
            end
            STATE_DATA_0:
            begin
                membr_done  <= 1'b0;
                out_ad  <= membr_data[7:0];
                out_stb <= 1'b0;
                state   <= STATE_DATA_1;
            end
            STATE_DATA_1:
            begin
                membr_done  <= 1'b0;
                out_ad  <= membr_data[15:8];
                out_stb <= 1'b0;
                state   <= STATE_DATA_2;
            end
            STATE_DATA_2:
            begin
                membr_done  <= 1'b0;
                out_ad  <= membr_data[23:16];
                out_stb <= 1'b0;
                state   <= STATE_DATA_3;
            end
            STATE_DATA_3:
            begin
                membr_done  <= 1'b0;
                out_ad  <= membr_data[31:24];
                out_stb <= 1'b0;
                state   <= STATE_IDLE;
            end
            default:
            begin
                membr_done  <= 1'b1;
                out_ad  <= 8'hff;
                out_stb <= 1'b0;
                state   <= STATE_IDLE;