Commit e2fb6292 authored by Andrey Filippov's avatar Andrey Filippov

Finished initial coding for PRD Host->Device modules

parent f1543888
...@@ -37,10 +37,12 @@ module ahci_dma_rd_fifo#( ...@@ -37,10 +37,12 @@ module ahci_dma_rd_fifo#(
input [63:0] din, input [63:0] din,
input din_av, input din_av,
input din_av_many, input din_av_many,
input flush, // last prd, flush partial dword if there were odd number of words transferred input last_prd, // last prd, flush partial dword if there were odd number of words transferred. valid @ start
// Or maybe use "last_prd"? // Or maybe use "last_prd"?
output din_re, output din_re,
output done, output reg done, // this PRD data sent to cross-clock FIFO (may result in only half-dword sent out),
// OK to fetch another PRD (if it was not the last)
output done_flush, // finished last PRD (indicated by last_prd @ start), data left module
// mclk domain // mclk domain
output [31:0] dout, output [31:0] dout,
output dout_vld, output dout_vld,
...@@ -51,14 +53,15 @@ module ahci_dma_rd_fifo#( ...@@ -51,14 +53,15 @@ module ahci_dma_rd_fifo#(
reg [ADDRESS_BITS+1:0] raddr; // 1 extra bit reg [ADDRESS_BITS+1:0] raddr; // 1 extra bit
reg [63:16] din_prev; // only 48 bits are needed reg [63:16] din_prev; // only 48 bits are needed
reg [WCNT_BITS-3:0] qwcntr; reg [WCNT_BITS-3:0] qwcntr;
reg some_offs; // reg some_offs;
reg extra_in; reg extra_in;
reg busy; reg busy;
reg din_last_w = din_re && (qwcntr==0); // reg din_last_w = din_re && (qwcntr==0);
wire [2:0] end_offs = wcnt[1:0] + woffs; wire [2:0] end_offs = wcnt[1:0] + woffs;
reg [63:0] fifo_ram [0: ADDRESS_NUM - 1]; reg [63:0] fifo_ram [0: ADDRESS_NUM - 1];
reg [3:0] vld_ram [0: ADDRESS_NUM - 1]; reg [3:0] vld_ram [0: ADDRESS_NUM - 1];
reg [1:0] flush_ram [0: ADDRESS_NUM - 1];
reg [(1<<ADDRESS_BITS)-1:0] fifo_full; // set in write clock domain reg [(1<<ADDRESS_BITS)-1:0] fifo_full; // set in write clock domain
reg [(1<<ADDRESS_BITS)-1:0] fifo_nempty;// set in read clock domain reg [(1<<ADDRESS_BITS)-1:0] fifo_nempty;// set in read clock domain
wire fifo_wr; wire fifo_wr;
...@@ -68,23 +71,43 @@ module ahci_dma_rd_fifo#( ...@@ -68,23 +71,43 @@ module ahci_dma_rd_fifo#(
// wire [(1<<ADDRESS_BITS)-1:0] fifo_nempty_half = {fifo_nempty[(ADDRESS_NUM>>1)-1:0],fifo_full[ADDRESS_NUM-1: ADDRESS_NUM>>1]}; // wire [(1<<ADDRESS_BITS)-1:0] fifo_nempty_half = {fifo_nempty[(ADDRESS_NUM>>1)-1:0],fifo_full[ADDRESS_NUM-1: ADDRESS_NUM>>1]};
reg fifo_dav; // @mclk reg fifo_dav; // @mclk
reg fifo_dav2; // @mclk reg fifo_dav2; // @mclk
reg fifo_half_hclk; reg fifo_half_hclk; // Half Fifo is empty, OK to write
reg [1:0] woffs_r; reg [1:0] woffs_r;
wire [63:0] fifo_di= woffs_r[1]?(woffs_r[0] ? {din[47:0],din_prev[63:48]} : {din[31:0],din_prev[63:32]}): wire [63:0] fifo_di= woffs_r[1]?(woffs_r[0] ? {din[47:0],din_prev[63:48]} : {din[31:0],din_prev[63:32]}):
(woffs_r[0] ? {din[15:0],din_prev[63:16]} : din[63:0]); (woffs_r[0] ? {din[15:0],din_prev[63:16]} : din[63:0]);
wire [3:0] fifo_di_vld; // Assign wire [3:0] fifo_di_vld;
wire [1:0] fifo_di_flush; // Assign
wire [63:0] fifo_do = fifo_ram [raddr[ADDRESS_BITS:1]];
wire [3:0] fifo_do_vld = vld_ram [raddr[ADDRESS_BITS:1]];
wire [1:0] fifo_do_flush = flush_ram[raddr[ADDRESS_BITS:1]];
reg din_av_safe_r;
reg en_fifo_wr;
reg [3:0] last_mask;
reg flush_r;
wire done_flush_mclk;
assign din_re = busy && fifo_half_hclk && din_av_safe_r;
assign fifo_wr = en_fifo_wr && fifo_half_hclk && (din_av_safe_r || !busy);
assign fifo_di_vld = (busy && (!extra_in || (qwcntr != 0)))? 4'hf : last_mask ;
assign fifo_di_flush = ((busy && (!extra_in || (qwcntr != 0))) || !flush_r)? 2'h0 : {|last_mask[3:2], ~(|last_mask[3:2])} ;
always @ (posedge hclk) begin always @ (posedge hclk) begin
if (hrst) busy <= 0; if (hrst) busy <= 0;
else if (start) busy <= 1; else if (start) busy <= 1;
else if (done) busy <= 0; else if (din_re && (qwcntr == 0)) busy <= 0;
done <= busy && din_re && (qwcntr == 0);
if (hrst) en_fifo_wr <= 0;
else if (start) en_fifo_wr <= (wcnt[1:0] == 0);
else if (din_re || fifo_wr) en_fifo_wr <= busy && ((qwcntr != 0) || extra_in);
if (start) qwcntr <= wcnt[WCNT_BITS-1:2]; if (start) qwcntr <= wcnt[WCNT_BITS-1:2];
else if (din_re) qwcntr <= qwcntr - 1; else if (din_re) qwcntr <= qwcntr - 1;
if (start) some_offs <= wcnt[1:0] != 0;
if (start) extra_in <= end_offs[2]; if (start) extra_in <= end_offs[2];
if (start) woffs_r <= woffs; if (start) woffs_r <= woffs;
...@@ -101,11 +124,23 @@ module ahci_dma_rd_fifo#( ...@@ -101,11 +124,23 @@ module ahci_dma_rd_fifo#(
if (fifo_wr) fifo_ram[waddr[ADDRESS_BITS-1:0]] <= fifo_di; if (fifo_wr) fifo_ram[waddr[ADDRESS_BITS-1:0]] <= fifo_di;
if (fifo_wr) vld_ram [waddr[ADDRESS_BITS-1:0]] <= fifo_di_vld; if (fifo_wr) vld_ram [waddr[ADDRESS_BITS-1:0]] <= fifo_di_vld;
if (fifo_wr) flush_ram[waddr[ADDRESS_BITS-1:0]] <= fifo_di_flush;
if (hrst) din_av_safe_r <= 0;
else din_av_safe_r <= din_av && (din_av_many || !din_re);
if (start) last_mask <= {&wcnt, wcnt[1], |wcnt, 1'b1};
if (start) flush_r <= last_prd;
end end
always @ (posedge hclk) begin always @ (posedge hclk) begin
hrst_mclk <= hrst; hrst_mclk <= hrst;
if (hrst_mclk) raddr <= 0;
else if (fifo_rd) raddr <= raddr + 1;
if (hrst_mclk) fifo_nempty <= {{(ADDRESS_NUM>>1){1'b0}},{(ADDRESS_NUM>>1){1'b1}}};// 8'b00001111 if (hrst_mclk) fifo_nempty <= {{(ADDRESS_NUM>>1){1'b0}},{(ADDRESS_NUM>>1){1'b1}}};// 8'b00001111
else if (fifo_rd && raddr[0]) fifo_nempty <= {fifo_nempty[ADDRESS_NUM-2:0],raddr[ADDRESS_BITS+1] ^ raddr[ADDRESS_BITS]}; else if (fifo_rd && raddr[0]) fifo_nempty <= {fifo_nempty[ADDRESS_NUM-2:0],raddr[ADDRESS_BITS+1] ^ raddr[ADDRESS_BITS]};
...@@ -116,19 +151,27 @@ module ahci_dma_rd_fifo#( ...@@ -116,19 +151,27 @@ module ahci_dma_rd_fifo#(
ahci_dma_rd_stuff ahci_dma_rd_stuff_i ( ahci_dma_rd_stuff ahci_dma_rd_stuff_i (
.rst (mrst), // input .rst (mrst), // input
.clk (mclk), // input .clk (mclk), // input
.din_av (), // input .din_av (fifo_dav), // input
.din_avm (), // input .din_avm (fifo_dav2), // input
.flush (), // input .flush (raddr[0]?fifo_do_flush[1]:fifo_do_flush[0]), // input
.din (), // input[31:0] .din (raddr[0]?fifo_do[63:32]: fifo_do[31:0]), // input[31:0]
.dm (), // input[1:0] .dm (raddr[0]?fifo_do_vld[3:2]:fifo_do_vld[1:0]), // input[1:0]
.din_re (), // output .din_re (fifo_rd), // output
.flushed (done_flush_mclk), // output reg: flush (end of last PRD is finished - data left module)
.dout (dout), // output[31:0] reg .dout (dout), // output[31:0] reg
.dout_vld (dout_vld), // output .dout_vld (dout_vld), // output
.dout_re (dout_re) // input .dout_re (dout_re) // input
); );
pulse_cross_clock #(
.EXTRA_DLY(0)
) done_flush_i (
.rst (mrst), // input
.src_clk (mclk), // input
.dst_clk (hclk), // input
.in_pulse (done_flush_mclk), // input
.out_pulse (done_flush), // output
.busy() // output
);
endmodule endmodule
...@@ -29,6 +29,7 @@ module ahci_dma_rd_stuff( ...@@ -29,6 +29,7 @@ module ahci_dma_rd_stuff(
input [31:0] din, // 32-bit input dfata input [31:0] din, // 32-bit input dfata
input [1:0] dm, // data mask showing which (if any) words in input dword are valid input [1:0] dm, // data mask showing which (if any) words in input dword are valid
output din_re, // read input data output din_re, // read input data
output reg flushed, // flush (end of last PRD is finished - data left module)
output reg [31:0] dout, // output 32-bit data output reg [31:0] dout, // output 32-bit data
output dout_vld, // output data valid output dout_vld, // output data valid
input dout_re // consumer reads output data (should be anded with dout_vld) input dout_re // consumer reads output data (should be anded with dout_vld)
...@@ -37,6 +38,7 @@ module ahci_dma_rd_stuff( ...@@ -37,6 +38,7 @@ module ahci_dma_rd_stuff(
reg hr_full; reg hr_full;
reg dout_vld_r; reg dout_vld_r;
reg flushing; reg flushing;
reg flushing_d;
reg din_av_safe_r; reg din_av_safe_r;
wire [1:0] dav_in = {2{din_av_safe_r}} & dm; wire [1:0] dav_in = {2{din_av_safe_r}} & dm;
wire two_words_avail = &dav_in || (|dav_in && hr_full); wire two_words_avail = &dav_in || (|dav_in && hr_full);
...@@ -72,6 +74,9 @@ module ahci_dma_rd_stuff( ...@@ -72,6 +74,9 @@ module ahci_dma_rd_stuff(
else if (flush) flushing <= 1; else if (flush) flushing <= 1;
else if ((!dout_vld_r || dout_re) && !(&dav_in && hr_full)) flushing <= 0; else if ((!dout_vld_r || dout_re) && !(&dav_in && hr_full)) flushing <= 0;
flushing_d <= flushing;
flushed <= flushing_d && !flushing; // 1 cycle delay
end end
endmodule endmodule
......
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