Commit d5b58b3a authored by Andrey Filippov's avatar Andrey Filippov

simulated H->D DMA data

parent 354a7663
......@@ -497,7 +497,7 @@ module ahci_dma (
.dout (sys_out), // output[31:0]
.dout_vld (sys_dav), // output
.dout_re (sys_re), // input
.last_data (last_h2d_data) // output
.last_DW (last_h2d_data) // output
);
ahci_dma_wr_fifo #( // device to memory
......
This diff is collapsed.
......@@ -37,59 +37,124 @@ module ahci_dma_rd_stuff(
input rst, // sync reset
input clk, // single clock
input din_av, // input data available
input din_avm, // >1 word of data available
input flush, // output partial dword if available (should be ? cycles after last _re/ with data?)
input din_avm_w,// >1 word of data available (early)
input din_avm, // >1 word of data available (registered din_avm_w)
input flushing, // output partial dword if available (should be ? cycles after last _re/ with data?)
input [31:0] din, // 32-bit input dfata
input [1:0] dm, // data mask showing which (if any) words in input dword are valid
output din_re, // read input data
output reg flushed, // flush (end of last PRD is finished - data left module)
output flushed, // flush (end of last PRD is finished - data left module)
output reg [31:0] dout, // output 32-bit data
output dout_vld, // output data valid
input dout_re // consumer reads output data (should be AND-ed with dout_vld)
input dout_re, // consumer reads output data (should be AND-ed with dout_vld)
output last_DW
);
reg [15:0] hr; // holds 16-bit data from previous din_re if not consumed
reg hr_full;
reg dout_vld_r;
reg flushing;
reg flushing_d;
reg [1:0] dout_vld_r;
reg din_av_safe_r;
reg din_re_r;
wire [1:0] dav_in = {2{din_av_safe_r}} & dm;
wire two_words_avail = &dav_in || (|dav_in && hr_full);
assign din_re = (din_av_safe_r && !(|dm)) || ((!dout_vld_r || dout_re) && (two_words_avail)) ; // flush
assign dout_vld = dout_vld_r;
always @ (posedge clk) begin
if (rst) din_av_safe_r <= 0;
else din_av_safe_r <= din_av && (din_avm || !din_re);
wire [1:0] drd_in = {2{din_re}} & dm;
if ((!dout_vld_r || dout_re) && (two_words_avail || flushing)) begin
if (hr_full) dout[15: 0] <= hr;
else dout[15: 0] <= din[15: 0];
if (hr_full && dav_in[0]) dout[31:16] <= din[15: 0];
else dout[31:16] <= din[31:16];
end
wire [15:0] debug_din_low = din[15: 0];
wire [15:0] debug_din_high = din[31:16];
wire [15:0] debug_dout_low = dout[15: 0];
wire [15:0] debug_dout_high = dout[31:16];
// wire empty_in = din_av_safe_r && !(|dm);
// wire two_words_avail = &dav_in || (|dav_in && hr_full);
wire more_words_avail = |dav_in || hr_full;
wire [1:0] next_or_empty = {2{dout_re}} | ~dout_vld_r;
/// assign din_re = (din_av_safe_r && !(|dm)) || ((!dout_vld_r || dout_re) && (two_words_avail)) ; // flush
// ---------------
// todo add reset/flush
if (rst) hr_full <= 0;
else if (!dout_vld_r || dout_re)
// 2 but not 3 sources available
if (flushing || ((two_words_avail) && ! (&dav_in && hr_full))) hr_full <= 0;
else if (dav_in[0] ^ dav_in[1]) hr_full <= 1;
wire room_for2 = dout_re || (!(&dout_vld_r) && !hr_full) || !(|dout_vld_r);
wire room_for1 = dout_re || !hr_full || !(&dout_vld_r);
reg slow_down; // first time fifo almost empty
reg slow_dav; // enable dout_vld waiting after each read out not to miss last DWORD
reg last_DW_r;
reg last_dw_sent;
wire no_new_data_w;
reg [1:0] no_new_data_r;
assign din_re = din_av_safe_r && (!(|dm) || room_for2 || (room_for1 && !(&dm)));
if ((!dout_vld_r || dout_re) && (&dav_in && hr_full)) hr <= din[31:16];
else if ((dav_in[0] ^ dav_in[1]) && !hr_full) hr <= dav_in[0]? din[15:0] : din[31:16];
/// assign dout_vld = (&dout_vld_r) || ((|dout_vld_r) && flushing);
assign dout_vld = (!slow_down && (&dout_vld_r)) || slow_dav;
assign last_DW = last_DW_r;
assign flushed = last_DW_r && dout_re;
assign no_new_data_w = !din_av && !hr_full;
// assign flushed =
always @ (posedge clk) begin
din_re_r <= din_re;
if (rst) din_av_safe_r <= 0;
else din_av_safe_r <= din_av && (din_avm || (!din_re && !din_re_r));
// set low word of the OR
if (rst) dout_vld_r[0] <= 0;
else if (next_or_empty[0]) dout_vld_r[0] <= hr_full || (din_re && (|dm));
if (next_or_empty[0]) begin
if (hr_full) dout[15: 0] <= hr;
else if (din_re) begin
if (dm[0]) dout[15: 0] <= din[15: 0];
else if (dm[1]) dout[15: 0] <= din[31:16];
end
end
// set high word of the OR
if (rst) dout_vld_r[1] <= 0;
else if (next_or_empty[1]) dout_vld_r[1] <= next_or_empty[0]?
(din_re && ((hr_full &&(|dm)) || (&dm))) :
(hr_full || (din_re && (|dm)));
if (next_or_empty[1]) begin
if (next_or_empty[0]) begin
if (din_re) begin
if (hr_full && dm[0]) dout[31:16] <= din[15: 0];
else if (dm[1] && (!hr_full || dm[0])) dout[31:16] <= din[31:16];
end
end else begin
if (hr_full) dout[31:16] <= hr;
else if (din_re) begin
if (dm[0]) dout[31:16] <= din[15: 0];
else if (dm[1]) dout[31:16] <= din[31:16];
end
end
end
if (rst) dout_vld_r <= 0;
else if ((!dout_vld_r || dout_re) && (two_words_avail || (flushing && hr_full))) dout_vld_r <= 1;
else if (dout_re) dout_vld_r <= 0;
// set holding register
if (rst) hr_full <= 0;
else if (((&next_or_empty) && !(&drd_in)) ||
((|next_or_empty) && !(|drd_in))) hr_full <= 0;
else if (((&drd_in) && !(&next_or_empty)) ||
((|drd_in) && !(|next_or_empty))) hr_full <= 1;
if (drd_in[1]) hr <= din[31:16];
else if (drd_in[0]) hr <= din[15: 0];
if (rst || !flushing) slow_down <= 0;
else if (!din_avm_w) slow_down <= 1;
if (rst) flushing <= 0;
else if (flush) flushing <= 1;
else if ((!dout_vld_r || dout_re) && !(&dav_in && hr_full)) flushing <= 0;
if (rst || !flushing || last_dw_sent) slow_dav <= 0;
else slow_dav <= !dout_re && !last_dw_sent && ((!next_or_empty[1] && more_words_avail) || last_DW_r);
flushing_d <= flushing;
flushed <= flushing_d && !flushing; // 1 cycle delay
if (rst || !flushing) last_dw_sent <= 0;
else if (last_DW_r && dout_re) last_dw_sent <= 1;
no_new_data_r <= {no_new_data_r[0], no_new_data_w};
if (rst || !flushing) last_DW_r <= 0;
else if (slow_down && no_new_data_w && (&no_new_data_r)) last_DW_r <= 1;
else if (dout_re) last_DW_r <= 0;
end
endmodule
......
......@@ -92,7 +92,7 @@ module ahci_fis_transmit #(
input [31:0] dma_out, // 32-bit data from the DMA module, HBA -> device port
input dma_dav, // at least one dword is ready to be read from DMA module
output dma_re, // read dword from DMA module to the output register
input last_h2d_data,// single pulse, after it watch for FIS end (no data for 2 clocks)
input last_h2d_data,// last dword in dma_out
// Data System memory or FIS -> device
output reg [31:0] todev_data, // 32-bit data from the system memory to HBA (dma data)
......@@ -114,6 +114,7 @@ module ahci_fis_transmit #(
// for fis_data_valid - longer latency
// wire fis_out_w = !dma_en_r && fis_data_valid && todev_ready;
wire dma_re_w = dma_en_r && dma_dav && todev_ready;
/// wire dma_re_w = dma_en_r && dma_dav && todev_ready && (!todev_full_r || !watch_prd_end_w);
reg [15:0] ch_prdtl_r;
reg ch_c_r;
......@@ -158,7 +159,7 @@ module ahci_fis_transmit #(
reg [11:0] dx_dwords_left;
reg dx_fis_pend_r; // waiting to send first DWORD of the H2D data transfer
wire dx_dma_last_w; // sending last adat word
wire dx_dma_last_w; // sending last data word
reg dx_busy_r;
reg [ 2:0] dx_err_r;
reg xmit_ok_r;
......@@ -168,16 +169,19 @@ module ahci_fis_transmit #(
wire done_w = xmit_ok_r || ((|dx_err_r) && dx_busy_r) || dma_start; // done on last transmit or error
reg fetch_cmd_busy_r;
reg xfer_cntr_not_set;
// now ahci_dma watches for the last data DWORD and generates last_h2d_data, so transmission will end if either of xfer counter or DMA data (defined by total prd size)
// if xfer_cntr wazs 0, it will never be decremented and never equal to 1, will not generate last)
// reg xfer_cntr_is_set;
// reg watch_prd_end;
// wire masked_last_h2d_data = xfer_cntr_not_set && last_h2d_data; // otherwise use xfer counter to find FIS end
// wire watch_prd_end_w = masked_last_h2d_data || watch_prd_end; // Maybe not needed - just use watch_prd_end
reg watch_prd_end;
wire masked_last_h2d_data = xfer_cntr_not_set && last_h2d_data; // otherwise use xfer counter to find FIS end
wire watch_prd_end_w = masked_last_h2d_data || watch_prd_end; // Maybe not needed - just use watch_prd_end
// reg [1:0] was_dma_re; // previous values of dma_re
reg [2:0] was_dma_ndav; // inverted/masked previous values of dma_dav
wire send_last_w = was_dma_ndav[2];
// assign todev_valid = todev_full_r;
assign todev_valid = todev_full_r && (!watch_prd_end_w || dma_dav || send_last_w);
// reg [2:0] was_dma_ndav; // inverted/masked previous values of dma_dav
// wire send_last_w = was_dma_ndav[2];
assign todev_valid = todev_full_r;
// assign todev_valid = todev_full_r && (!watch_prd_end_w || dma_dav || send_last_w);
assign dma_re = dma_re_w;
assign reg_re = reg_re_r[1:0];
......@@ -196,20 +200,25 @@ module ahci_fis_transmit #(
assign pCmdToIssue = pCmdToIssue_r;
// assign dmaCntrZero = dmaCntrZero_r;
assign ct_re = ct_re_r[1:0];
assign fis_data_valid = ct_stb; // no wait write to output register 'todev_data', ct_re_r[0] is throttled according to FIFO room availability
/// assign fis_data_valid = ct_stb; // no wait write to output register 'todev_data', ct_re_r[0] is throttled according to FIFO room availability
// What else to wait for when
assign fis_data_valid = ct_stb || (!dma_ct_busy && dx_fis_pend_r); // no wait write to output register 'todev_data', ct_re_r[0] is throttled according to FIFO room availability
assign ct_re_w = todev_ready && ((cfis_acmd_left_r[4:1] != 0) || (cfis_acmd_left_r[0] && !ct_re_r[0])); // Later add more sources
assign fis_dw_last = (cfis_acmd_left_out_r == 1);
assign fis_data_type = {fis_dw_last, (write_or_w && dx_fis_pend_r) | (fis_dw_first && ct_stb)};
assign fis_data_out = ({32{dx_fis_pend_r}} & DATA_FIS) | ({32{ct_stb}} & ct_data) ;
assign dx_dma_last_w = dma_en_r && dma_re_w && (dx_dwords_left[11:0] == 1);
assign dx_dma_last_w = dma_en_r && dma_re_w && ((dx_dwords_left[11:0] == 1) || last_h2d_data);
assign dx_err = dx_err_r;
assign dma_dev_wr = ch_w_r;
/// assign write_or_w = (dma_en_r?(dma_dav && todev_ready && ()):fis_data_valid); // do not fill the buffer if FIFO is not ready for DMA,
assign write_or_w = (dma_en_r?(dma_dav && todev_ready && (!todev_full_r || watch_prd_end_w)):fis_data_valid); // do not fill the buffer if FIFO is not ready for DMA,
// When watching for FIS end, do not fill/use output register in the same cycle
/// assign write_or_w = (dma_en_r?(dma_dav && todev_ready ):fis_data_valid); // do not fill the buffer if FIFO is not ready for DMA,
/// assign write_or_w = (dma_en_r?(dma_dav && todev_ready && (!todev_full_r || !watch_prd_end_w)):fis_data_valid); // do not fill the buffer if FIFO is not ready for DMA,
assign write_or_w = dma_re_w || fis_data_valid;
// When watching for FIS end, do not fill/use output register in the same cycle
always @ (posedge mclk) begin
// Mutliplex between DMA and FIS output to the output routed to transmit FIFO
// Count bypassing DMA dwords to generate FIS_last condition?
......@@ -220,14 +229,17 @@ module ahci_fis_transmit #(
if (write_or_w) todev_data <= dma_en_r? dma_out: fis_data_out;
if (hba_rst) todev_type <= 3; // invalid? - no, now first and last word in command FIS (impossible?)
else if (write_or_w) todev_type <= dma_en_r? {dx_dma_last_w, 1'b0} : fis_data_type;
else if (was_dma_ndav[1]) todev_type <= {1'b1, 1'b0}; // type = last in FIS
else if (write_or_w) todev_type <= dma_en_r? {dx_dma_last_w , 1'b0} : fis_data_type;
// else if (was_dma_ndav[1]) todev_type <= {1'b1, 1'b0}; // type = last in FIS
// if (hba_rst) was_dma_ndav <= 0;
// else was_dma_ndav <= {was_dma_ndav[1:0], ~dma_dav & todev_full_r & watch_prd_end_w} ;
if (hba_rst) was_dma_ndav <= 0;
else was_dma_ndav <= {was_dma_ndav[1:0], ~dma_dav & todev_full_r & watch_prd_end_w} ;
// if (hba_rst || dma_dav || !todev_full_r || !watch_prd_end_w) was_dma_ndav <= 0;
// else was_dma_ndav <= (was_dma_ndav << 1) | 1;
if (hba_rst || dx_xmit || done_w) watch_prd_end <= 0;
else if (masked_last_h2d_data) watch_prd_end <= 1;
// if (hba_rst || dx_xmit || done_w) watch_prd_end <= 0;
// else if (masked_last_h2d_data) watch_prd_end <= 1;
// Read 3 DWORDs from the command header
if (hba_rst) fetch_chead_r <= 0; // running 1
......@@ -309,7 +321,7 @@ module ahci_fis_transmit #(
//TODO: update xfer length, prdtl (only after R_OK) - yes, do it outside
if (dx_xmit) xfer_cntr_not_set <= xfer_cntr_zero; // if it was zero - rely on PRDs
// if (dx_xmit) xfer_cntr_is_set <= !xfer_cntr_zero; // if it was zero - rely on PRDs
if (dx_xmit) dx_dwords_left[11:0] <= (xfer_cntr_zero || (|xfer_cntr[31:13])) ? 12'h800 : {1'b0,xfer_cntr[12:2]};
else if (dma_re_w) dx_dwords_left[11:0] <= dx_dwords_left[11:0] - 1;
......
......@@ -328,13 +328,15 @@ task linkMonitorFIS;
input integer id;
input integer dmat_index;
output integer status;
reg [112:0] rprim;
reg [111:0] rprim;
integer pause;
integer rcv_stop;
integer rcv_ignore;
integer cnt;
reg [31:0] descrambled_data;
reg [31:0] scrambler_value;
reg [31:0] crc;
reg crc_match;
begin
pause = receive_wait_fifo;
status = 0;
......@@ -485,29 +487,38 @@ task linkMonitorFIS;
rcv_stop = 2;
end
if ((rcv_stop == 0) && (rcv_ignore == 0)) begin
if (cnt > 2048) begin
// $display("[Device] LINK: Wrong data dwords count received, reception id = %d", id);
DEV_TITLE = "Wrong data dwords count received";
if (rprim == "ALIGN") begin
DEV_TITLE = "ALIGN got";
DEV_DATA = id;
$display("[Device] LINK: %s, reception id = %d @%t", DEV_TITLE, DEV_DATA, $time);
$finish;
end
if (cnt >= dmat_index) begin
linkSendPrim("DMAT");
end
// scrambler_value = scrambleFunc(scrambler_value[31:16]);
scrambler_value = scrambleFunc({16'b0,scrambler_value[31:16]});
receive_data[cnt] = linkGetData(0) ^ scrambler_value;
// $display("[Device] LINK: Got data = %h", receive_data[cnt]);
DEV_TITLE = "Got data";
DEV_DATA = receive_data[cnt];
$display("[Device] LINK: %s = %h @%t", DEV_TITLE, DEV_DATA, $time);
pause = pause + receive_data_pause[cnt];
crc = calculateCRC(crc, receive_data[cnt]); // running crc. shall be 0
cnt = cnt + 1;
if (cnt <= 2048)
$display("[Device] LINK: %s, reception id = %d, cnt = %d @%t", DEV_TITLE, DEV_DATA, cnt, $time);
end else begin
if (cnt > 2048) begin
// $display("[Device] LINK: Wrong data dwords count received, reception id = %d", id);
DEV_TITLE = "Wrong data dwords count received";
DEV_DATA = id;
$display("[Device] LINK: %s, reception id = %d @%t", DEV_TITLE, DEV_DATA, $time);
$finish;
end
if (cnt >= dmat_index) begin
linkSendPrim("DMAT");
end
scrambler_value = scrambleFunc({16'b0,scrambler_value[31:16]});
/// receive_data[cnt] = linkGetData(0) ^ scrambler_value;
descrambled_data = linkGetData(0) ^ scrambler_value;
receive_data[cnt] = descrambled_data;
DEV_TITLE = "Got data";
DEV_DATA = receive_data[cnt];
$display("[Device] LINK: %s = %h (#%d) @%t", DEV_TITLE, DEV_DATA, cnt, $time);
pause = pause + receive_data_pause[cnt];
crc_match = (crc == descrambled_data);
crc = calculateCRC(crc, descrambled_data); // running crc. shall be 0
// crc_match = (crc == receive_data[cnt]);
cnt = cnt + 1;
if (cnt <= 2048)
pause = pause + receive_data_pause[cnt];
end
end
@ (posedge clk)
rprim = linkGetPrim(0);
......@@ -523,7 +534,8 @@ task linkMonitorFIS;
DEV_DATA = crc;
$display("[Device] LINK: %s = %h @%t", DEV_TITLE, DEV_DATA, $time);
if (crc != 32'h88c21025) begin // running disparity when data crc matches actual received crc
// if (crc != 32'h88c21025) begin // running disparity when data crc matches actual received crc
if (!crc_match) begin // running disparity when data crc matches actual received crc
// $display("[Device] LINK: Running CRC check failed");
DEV_TITLE = "Running CRC check failed";
$display("[Device] LINK: %s @%t", DEV_TITLE, $time);
......@@ -766,7 +778,7 @@ task linkTransmitFIS; // @SuppressThisWarning VEditor - Used in testbench
integer pause;
integer cnt;
integer crc;
reg [112:0] rprim;
reg [111:0] rprim;
reg [31:0] scrambler_value;
begin
crc = 32'h52325032;// crc seed
......@@ -1018,9 +1030,9 @@ endfunction
* Returns current primitive at the outputs of phy level
* Return value is a string containing its name!
*/
function [112:0] linkGetPrim;
function [111:0] linkGetPrim;
input integer dummy; // @SuppressThisWarning VEditor - unused (is it for some simulator?)
reg [112:0] type;
reg [111:0] type;
begin
if (~|phy2dev_charisk) begin
type = "DATA";
......@@ -1082,7 +1094,7 @@ endtask
* input is a string containing its name!
*/
task linkSendPrim;
input [112:0] type;
input [111:0] type;
begin
case (type)
"SYNC":
......
......@@ -546,6 +546,7 @@ always @ (posedge clk)
// incoming data is data
wire inc_is_data;
assign inc_is_data = dword_val & rcvd_dword[CODE_DATA] & (state_rcvr_data | state_rcvr_rhold);
//wire inc_is_crc = dword_val & rcvd_dword[CODE_CRC] & (state_rcvr_data | state_rcvr_rhold);
/*
* Scrambler can work both as a scrambler and a descramler, because data stream could be
* one direction at a time
......@@ -553,7 +554,7 @@ assign inc_is_data = dword_val & rcvd_dword[CODE_DATA] & (state_rcvr_data | sta
scrambler scrambler(
.rst (select_prim[CODE_SOFP] | dword_val & rcvd_dword[CODE_SOFP]),
.clk (clk),
.val_in (select_prim[CODE_DATA] | inc_is_data),
.val_in (select_prim[CODE_DATA] | inc_is_data | select_prim[CODE_CRC]),
.data_in (crc_dword & {DATA_BYTE_WIDTH*8{select_prim[CODE_CRC]}} |
data_in & {DATA_BYTE_WIDTH*8{select_prim[CODE_DATA]}} |
phy_data_in_r & {DATA_BYTE_WIDTH*8{inc_is_data}}),
......
......@@ -1051,6 +1051,8 @@ end
initial begin
// #30000;
#50000;
// #29630;
// #30000;
// #250000;
// #60000;
$display("finish testbench 2");
......
This diff is collapsed.
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