yesdingsheng,
Seems to me that you need a streaming PIO. Streaming is a seldom-used facet of the Avalon bus, but it fits the bill here. The HDL below implements a write-only streaming register; you can drive it from a DMA. You didn't say what version of the tools you have. The HDL should be importable from the Component Editor, or from the User Defined Interface with a bit more work. The new component should be defined as an Avalon Register Slave with 0 write wait states. Edit the Verilog parameters to suit your application. Let me know if this works for you.
module streaming_pio (
// inputs:
clk,
reset_n,
write_n,
writedata,
// outputs:
readyfordata,
pio_output
);
parameter DATA_WIDTH = 14;
parameter OUTPUT_RATE_HZ = 5000000;
parameter CLOCK_RATE_HZ = 50000000;
parameter PIO_RESET_VALUE = 0;
// Calculated parameter (not editable in GUI).
parameter RELOAD_VALUE = ((CLOCK_RATE_HZ / OUTPUT_RATE_HZ) - 1);
input clk;
input reset_n;
input write_n;
input [(DATA_WIDTH - 1) : 0] writedata;
output readyfordata;
output [(DATA_WIDTH - 1) : 0] pio_output;
reg [31 : 0] counter;
wire [31 : 0] p1_counter =
(~readyfordata & |counter) ? (counter - 1) :
(~write_n & readyfordata) ? RELOAD_VALUE :
counter;
always @(posedge clk or negedge reset_n) begin
if (~reset_n) begin
counter <= RELOAD_VALUE;
end
else begin
counter <= p1_counter;
end
end
wire readyfordata = ~|counter;
reg [(DATA_WIDTH - 1) : 0] pio_output;
wire [(DATA_WIDTH - 1) : 0] p1_pio_output =
~write_n & readyfordata ? writedata :
pio_output;
always @(posedge clk or negedge reset_n) begin
if (~reset_n) begin
pio_output <= PIO_RESET_VALUE;
end
else begin
pio_output <= p1_pio_output;
end
end
endmodule