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

dma_adapter rtl done

parent 6a13fd70
......@@ -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;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment