mirror of
https://github.com/WangXuan95/FPGA-DDR-SDRAM.git
synced 2025-01-30 02:32:53 +08:00
change to Verilog2001
This commit is contained in:
parent
6b9791c1fb
commit
ffa1fe0414
@ -2,8 +2,8 @@
|
|||||||
//--------------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------------
|
||||||
// Module : ddr_sdram_ctrl
|
// Module : ddr_sdram_ctrl
|
||||||
// Type : synthesizable, IP's top
|
// Type : synthesizable, IP's top
|
||||||
// Standard: SystemVerilog 2005 (IEEE1800-2005)
|
// Standard: Verilog 2001 (IEEE1364-2001)
|
||||||
// Function: DDR-SDRAM (DDR1) controller
|
// Function: DDR1 SDRAM controller
|
||||||
// with AXI4 interface
|
// with AXI4 interface
|
||||||
//--------------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
@ -59,18 +59,32 @@ module ddr_sdram_ctrl #(
|
|||||||
inout [ (4<<DQ_LEVEL)-1:0] ddr_dq
|
inout [ (4<<DQ_LEVEL)-1:0] ddr_dq
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
localparam DQS_BITS = ((1<<DQ_LEVEL)+1)/2;
|
localparam DQS_BITS = ((1<<DQ_LEVEL)+1)/2;
|
||||||
|
|
||||||
reg clk2 = '0;
|
reg clk2 = 1'b0;
|
||||||
reg init_done = '0;
|
reg init_done = 1'b0;
|
||||||
reg [2:0] ref_idle = 3'd1, ref_real = '0;
|
reg [2:0] ref_idle = 3'd1, ref_real = 3'd0;
|
||||||
reg [9:0] ref_cnt = '0;
|
reg [9:0] ref_cnt = 10'd0;
|
||||||
reg [7:0] cnt = '0;
|
reg [7:0] cnt = 8'd0;
|
||||||
enum logic [3:0] {RESET, IDLE, CLEARDLL, REFRESH, WPRE, WRITE, WRESP, WWAIT, RPRE, READ, RRESP, RWAIT} stat = RESET;
|
|
||||||
|
|
||||||
reg [7:0] burst_len = '0;
|
localparam [3:0] RESET = 4'd0,
|
||||||
|
IDLE = 4'd1,
|
||||||
|
CLEARDLL = 4'd2,
|
||||||
|
REFRESH = 4'd3,
|
||||||
|
WPRE = 4'd4,
|
||||||
|
WRITE = 4'd5,
|
||||||
|
WRESP = 4'd6,
|
||||||
|
WWAIT = 4'd7,
|
||||||
|
RPRE = 4'd8,
|
||||||
|
READ = 4'd9,
|
||||||
|
RRESP = 4'd10,
|
||||||
|
RWAIT = 4'd11;
|
||||||
|
reg [3:0] stat = RESET;
|
||||||
|
|
||||||
|
reg [7:0] burst_len = 8'd0;
|
||||||
wire burst_last = cnt==burst_len;
|
wire burst_last = cnt==burst_len;
|
||||||
reg [COL_BITS-2:0] col_addr = '0;
|
reg [COL_BITS-2:0] col_addr = 0;
|
||||||
|
|
||||||
wire [ROW_BITS-1:0] ddr_a_col;
|
wire [ROW_BITS-1:0] ddr_a_col;
|
||||||
generate if(COL_BITS>10) begin
|
generate if(COL_BITS>10) begin
|
||||||
@ -80,69 +94,70 @@ end else begin
|
|||||||
end endgenerate
|
end endgenerate
|
||||||
|
|
||||||
wire read_accessible, read_respdone;
|
wire read_accessible, read_respdone;
|
||||||
reg output_enable='0, output_enable_d1='0, output_enable_d2='0;
|
reg output_enable=1'b0, output_enable_d1=1'b0, output_enable_d2=1'b0;
|
||||||
|
|
||||||
reg o_v_a = '0;
|
reg o_v_a = 1'b0;
|
||||||
reg [(4<<DQ_LEVEL)-1:0] o_dh_a = '0;
|
reg [(4<<DQ_LEVEL)-1:0] o_dh_a = 0;
|
||||||
reg [(4<<DQ_LEVEL)-1:0] o_dl_a = '0;
|
reg [(4<<DQ_LEVEL)-1:0] o_dl_a = 0;
|
||||||
reg o_v_b = '0;
|
reg o_v_b = 1'b0;
|
||||||
reg [(4<<DQ_LEVEL)-1:0] o_dh_b = '0;
|
reg [(4<<DQ_LEVEL)-1:0] o_dh_b = 0;
|
||||||
reg o_dqs_c = '0;
|
reg o_dqs_c = 1'b0;
|
||||||
reg [(4<<DQ_LEVEL)-1:0] o_d_c = '0;
|
reg [(4<<DQ_LEVEL)-1:0] o_d_c = 0;
|
||||||
reg [(4<<DQ_LEVEL)-1:0] o_d_d = '0;
|
reg [(4<<DQ_LEVEL)-1:0] o_d_d = 0;
|
||||||
|
|
||||||
reg i_v_a = '0;
|
reg i_v_a = 1'b0;
|
||||||
reg i_l_a = '0;
|
reg i_l_a = 1'b0;
|
||||||
reg i_v_b = '0;
|
reg i_v_b = 1'b0;
|
||||||
reg i_l_b = '0;
|
reg i_l_b = 1'b0;
|
||||||
reg i_v_c = '0;
|
reg i_v_c = 1'b0;
|
||||||
reg i_l_c = '0;
|
reg i_l_c = 1'b0;
|
||||||
reg i_dqs_c = '0;
|
reg i_dqs_c = 1'b0;
|
||||||
reg [(4<<DQ_LEVEL)-1:0] i_d_c = '0;
|
reg [(4<<DQ_LEVEL)-1:0] i_d_c = 0;
|
||||||
reg i_v_d = '0;
|
reg i_v_d = 1'b0;
|
||||||
reg i_l_d = '0;
|
reg i_l_d = 1'b0;
|
||||||
reg [(8<<DQ_LEVEL)-1:0] i_d_d = '0;
|
reg [(8<<DQ_LEVEL)-1:0] i_d_d = 0;
|
||||||
reg i_v_e = '0;
|
reg i_v_e = 1'b0;
|
||||||
reg i_l_e = '0;
|
reg i_l_e = 1'b0;
|
||||||
reg [(8<<DQ_LEVEL)-1:0] i_d_e = '0;
|
reg [(8<<DQ_LEVEL)-1:0] i_d_e = 0;
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------------
|
||||||
// constants defination and assignment
|
// constants defination and assignment
|
||||||
// -------------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------------
|
||||||
localparam [ROW_BITS-1:0] DDR_A_DEFAULT = (ROW_BITS)'('b0100_0000_0000);
|
localparam [ROW_BITS-1:0] DDR_A_DEFAULT = 'b0100_0000_0000;
|
||||||
localparam [ROW_BITS-1:0] DDR_A_MR0 = (ROW_BITS)'('b0001_0010_1001);
|
localparam [ROW_BITS-1:0] DDR_A_MR0 = 'b0001_0010_1001;
|
||||||
localparam [ROW_BITS-1:0] DDR_A_MR_CLEAR_DLL = (ROW_BITS)'('b0000_0010_1001);
|
localparam [ROW_BITS-1:0] DDR_A_MR_CLEAR_DLL = 'b0000_0010_1001;
|
||||||
|
|
||||||
|
|
||||||
initial ddr_cs_n = 1'b1;
|
initial ddr_cs_n = 1'b1;
|
||||||
initial ddr_ras_n = 1'b1;
|
initial ddr_ras_n = 1'b1;
|
||||||
initial ddr_cas_n = 1'b1;
|
initial ddr_cas_n = 1'b1;
|
||||||
initial ddr_we_n = 1'b1;
|
initial ddr_we_n = 1'b1;
|
||||||
initial ddr_ba = '0;
|
initial ddr_ba = 0;
|
||||||
initial ddr_a = DDR_A_DEFAULT;
|
initial ddr_a = DDR_A_DEFAULT;
|
||||||
|
|
||||||
initial {rstn, clk} = '0;
|
initial rstn = 1'b0;
|
||||||
|
initial clk = 1'b0;
|
||||||
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------------
|
||||||
// generate reset sync with drv_clk
|
// generate reset sync with drv_clk
|
||||||
// -------------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------------
|
||||||
reg rstn_clk = '0;
|
reg rstn_clk = 1'b0;
|
||||||
reg [2:0] rstn_clk_l = '0;
|
reg [2:0] rstn_clk_l = 3'b0;
|
||||||
always @ (posedge drv_clk or negedge rstn_async)
|
always @ (posedge drv_clk or negedge rstn_async)
|
||||||
if(~rstn_async)
|
if(~rstn_async)
|
||||||
{rstn_clk, rstn_clk_l} <= '0;
|
{rstn_clk, rstn_clk_l} <= 4'b0;
|
||||||
else
|
else
|
||||||
{rstn_clk, rstn_clk_l} <= {rstn_clk_l, 1'b1};
|
{rstn_clk, rstn_clk_l} <= {rstn_clk_l, 1'b1};
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------------
|
||||||
// generate reset sync with clk
|
// generate reset sync with clk
|
||||||
// -------------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------------
|
||||||
reg rstn_aclk = '0;
|
reg rstn_aclk = 1'b0;
|
||||||
reg [2:0] rstn_aclk_l = '0;
|
reg [2:0] rstn_aclk_l = 3'b0;
|
||||||
always @ (posedge clk or negedge rstn_async)
|
always @ (posedge clk or negedge rstn_async)
|
||||||
if(~rstn_async)
|
if(~rstn_async)
|
||||||
{rstn_aclk, rstn_aclk_l} <= '0;
|
{rstn_aclk, rstn_aclk_l} <= 4'b0;
|
||||||
else
|
else
|
||||||
{rstn_aclk, rstn_aclk_l} <= {rstn_aclk_l, 1'b1};
|
{rstn_aclk, rstn_aclk_l} <= {rstn_aclk_l, 1'b1};
|
||||||
|
|
||||||
@ -169,14 +184,14 @@ always @ (posedge clk or negedge rstn_aclk)
|
|||||||
// -------------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------------
|
||||||
always @ (posedge clk or negedge rstn_aclk)
|
always @ (posedge clk or negedge rstn_aclk)
|
||||||
if(~rstn_aclk) begin
|
if(~rstn_aclk) begin
|
||||||
ref_cnt <= '0;
|
ref_cnt <= 10'd0;
|
||||||
ref_idle <= 3'd1;
|
ref_idle <= 3'd1;
|
||||||
end else begin
|
end else begin
|
||||||
if(init_done) begin
|
if(init_done) begin
|
||||||
if(ref_cnt<tREFC) begin
|
if(ref_cnt<tREFC) begin
|
||||||
ref_cnt <= ref_cnt + 10'd1;
|
ref_cnt <= ref_cnt + 10'd1;
|
||||||
end else begin
|
end else begin
|
||||||
ref_cnt <= '0;
|
ref_cnt <= 10'd0;
|
||||||
ref_idle <= ref_idle + 3'd1;
|
ref_idle <= ref_idle + 3'd1;
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -192,16 +207,16 @@ assign ddr_cke = ~ddr_cs_n;
|
|||||||
// -------------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------------
|
||||||
// generate DDR DQ output behavior
|
// generate DDR DQ output behavior
|
||||||
// -------------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------------
|
||||||
assign ddr_dm = output_enable ? '0 : 'z;
|
assign ddr_dm = output_enable ? {DQS_BITS{1'b0}} : {DQS_BITS{1'bz}};
|
||||||
assign ddr_dqs = output_enable ? {DQS_BITS{o_dqs_c}} : 'z;
|
assign ddr_dqs = output_enable ? {DQS_BITS{o_dqs_c}} : {DQS_BITS{1'bz}};
|
||||||
assign ddr_dq = output_enable ? o_d_d : 'z;
|
assign ddr_dq = output_enable ? o_d_d : {(4<<DQ_LEVEL){1'bz}};
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------------
|
||||||
// assignment for user interface (AXI4)
|
// assignment for user interface (AXI4)
|
||||||
// -------------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------------
|
||||||
assign awready = stat==IDLE && init_done && ref_real==ref_idle;
|
assign awready = stat==IDLE && init_done && ref_real==ref_idle;
|
||||||
assign wready = stat==WRITE;
|
assign wready = stat==WRITE;
|
||||||
assign bvalid = stat==WRESP;
|
assign bvalid = stat==WRESP;
|
||||||
assign arready = stat==IDLE && init_done && ref_real==ref_idle && ~awvalid && read_accessible;
|
assign arready = stat==IDLE && init_done && ref_real==ref_idle && ~awvalid && read_accessible;
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------------
|
||||||
@ -213,10 +228,10 @@ always @ (posedge clk or negedge rstn_aclk)
|
|||||||
ddr_ras_n <= 1'b1;
|
ddr_ras_n <= 1'b1;
|
||||||
ddr_cas_n <= 1'b1;
|
ddr_cas_n <= 1'b1;
|
||||||
ddr_we_n <= 1'b1;
|
ddr_we_n <= 1'b1;
|
||||||
ddr_ba <= '0;
|
ddr_ba <= 0;
|
||||||
ddr_a <= DDR_A_DEFAULT;
|
ddr_a <= DDR_A_DEFAULT;
|
||||||
col_addr <= '0;
|
col_addr <= 0;
|
||||||
burst_len <= '0;
|
burst_len <= 8'd0;
|
||||||
init_done <= 1'b0;
|
init_done <= 1'b0;
|
||||||
ref_real <= 3'd0;
|
ref_real <= 3'd0;
|
||||||
cnt <= 8'd0;
|
cnt <= 8'd0;
|
||||||
@ -238,10 +253,10 @@ always @ (posedge clk or negedge rstn_aclk)
|
|||||||
ddr_ras_n <= 1'b0;
|
ddr_ras_n <= 1'b0;
|
||||||
ddr_cas_n <= 1'b0;
|
ddr_cas_n <= 1'b0;
|
||||||
ddr_we_n <= 1'b0;
|
ddr_we_n <= 1'b0;
|
||||||
ddr_ba <= 'h1;
|
ddr_ba <= 1;
|
||||||
ddr_a <= '0;
|
ddr_a <= 0;
|
||||||
end else begin
|
end else begin
|
||||||
ddr_ba <= '0;
|
ddr_ba <= 0;
|
||||||
ddr_a <= DDR_A_MR0;
|
ddr_a <= DDR_A_MR0;
|
||||||
stat <= IDLE;
|
stat <= IDLE;
|
||||||
end
|
end
|
||||||
@ -250,7 +265,7 @@ always @ (posedge clk or negedge rstn_aclk)
|
|||||||
ddr_ras_n <= 1'b1;
|
ddr_ras_n <= 1'b1;
|
||||||
ddr_cas_n <= 1'b1;
|
ddr_cas_n <= 1'b1;
|
||||||
ddr_we_n <= 1'b1;
|
ddr_we_n <= 1'b1;
|
||||||
ddr_ba <= '0;
|
ddr_ba <= 0;
|
||||||
ddr_a <= DDR_A_DEFAULT;
|
ddr_a <= DDR_A_DEFAULT;
|
||||||
cnt <= 8'd0;
|
cnt <= 8'd0;
|
||||||
if(ref_real != ref_idle) begin
|
if(ref_real != ref_idle) begin
|
||||||
@ -317,7 +332,7 @@ always @ (posedge clk or negedge rstn_aclk)
|
|||||||
ddr_we_n <= 1'b0;
|
ddr_we_n <= 1'b0;
|
||||||
col_addr <= col_addr + {{(COL_BITS-2){1'b0}}, 1'b1};
|
col_addr <= col_addr + {{(COL_BITS-2){1'b0}}, 1'b1};
|
||||||
if(burst_last | wlast) begin
|
if(burst_last | wlast) begin
|
||||||
cnt <= '0;
|
cnt <= 8'd0;
|
||||||
stat <= WRESP;
|
stat <= WRESP;
|
||||||
end else begin
|
end else begin
|
||||||
cnt <= cnt + 8'd1;
|
cnt <= cnt + 8'd1;
|
||||||
@ -349,7 +364,7 @@ always @ (posedge clk or negedge rstn_aclk)
|
|||||||
ddr_a <= ddr_a_col;
|
ddr_a <= ddr_a_col;
|
||||||
col_addr <= col_addr + {{(COL_BITS-2){1'b0}}, 1'b1};
|
col_addr <= col_addr + {{(COL_BITS-2){1'b0}}, 1'b1};
|
||||||
if(burst_last) begin
|
if(burst_last) begin
|
||||||
cnt <= '0;
|
cnt <= 8'd0;
|
||||||
stat <= RRESP;
|
stat <= RRESP;
|
||||||
end else begin
|
end else begin
|
||||||
cnt <= cnt + 8'd1;
|
cnt <= cnt + 8'd1;
|
||||||
@ -390,7 +405,7 @@ always @ (posedge clk or negedge rstn)
|
|||||||
always @ (posedge clk or negedge rstn)
|
always @ (posedge clk or negedge rstn)
|
||||||
if(~rstn) begin
|
if(~rstn) begin
|
||||||
o_v_a <= 1'b0;
|
o_v_a <= 1'b0;
|
||||||
{o_dh_a, o_dl_a} <= '0;
|
{o_dh_a, o_dl_a} <= 0;
|
||||||
end else begin
|
end else begin
|
||||||
o_v_a <= (stat==WRITE && wvalid);
|
o_v_a <= (stat==WRITE && wvalid);
|
||||||
{o_dh_a, o_dl_a} <= wdata;
|
{o_dh_a, o_dl_a} <= wdata;
|
||||||
@ -402,7 +417,7 @@ always @ (posedge clk or negedge rstn)
|
|||||||
always @ (posedge clk or negedge rstn)
|
always @ (posedge clk or negedge rstn)
|
||||||
if(~rstn) begin
|
if(~rstn) begin
|
||||||
o_v_b <= 1'b0;
|
o_v_b <= 1'b0;
|
||||||
o_dh_b <= '0;
|
o_dh_b <= 0;
|
||||||
end else begin
|
end else begin
|
||||||
o_v_b <= o_v_a;
|
o_v_b <= o_v_a;
|
||||||
o_dh_b <= o_dh_a;
|
o_dh_b <= o_dh_a;
|
||||||
@ -412,12 +427,18 @@ always @ (posedge clk or negedge rstn)
|
|||||||
// dq and dqs generate for output (write)
|
// dq and dqs generate for output (write)
|
||||||
// -------------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------------
|
||||||
always @ (posedge clk2)
|
always @ (posedge clk2)
|
||||||
if(~clk) begin
|
if (~clk) begin
|
||||||
o_dqs_c <= 1'b0;
|
o_dqs_c <= 1'b0;
|
||||||
o_d_c <= o_v_a ? o_dl_a : '0;
|
if (o_v_a)
|
||||||
|
o_d_c <= o_dl_a;
|
||||||
|
else
|
||||||
|
o_d_c <= 0;
|
||||||
end else begin
|
end else begin
|
||||||
o_dqs_c <= o_v_b;
|
o_dqs_c <= o_v_b;
|
||||||
o_d_c <= o_v_b ? o_dh_b : '0;
|
if (o_v_b)
|
||||||
|
o_d_c <= o_dh_b;
|
||||||
|
else
|
||||||
|
o_d_c <= 0;
|
||||||
end
|
end
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------------
|
||||||
@ -440,8 +461,8 @@ always @ (posedge clk2)
|
|||||||
|
|
||||||
always @ (posedge clk or negedge rstn)
|
always @ (posedge clk or negedge rstn)
|
||||||
if(~rstn) begin
|
if(~rstn) begin
|
||||||
{i_v_a, i_v_b, i_v_c, i_v_d} <= '0;
|
{i_v_a, i_v_b, i_v_c, i_v_d} <= 0;
|
||||||
{i_l_a, i_l_b, i_l_c, i_l_d} <= '0;
|
{i_l_a, i_l_b, i_l_c, i_l_d} <= 0;
|
||||||
end else begin
|
end else begin
|
||||||
i_v_a <= stat==READ ? 1'b1 : 1'b0;
|
i_v_a <= stat==READ ? 1'b1 : 1'b0;
|
||||||
i_l_a <= burst_last;
|
i_l_a <= burst_last;
|
||||||
@ -457,7 +478,7 @@ always @ (posedge clk or negedge rstn)
|
|||||||
if(~rstn) begin
|
if(~rstn) begin
|
||||||
i_v_e <= 1'b0;
|
i_v_e <= 1'b0;
|
||||||
i_l_e <= 1'b0;
|
i_l_e <= 1'b0;
|
||||||
i_d_e <= '0;
|
i_d_e <= 0;
|
||||||
end else begin
|
end else begin
|
||||||
i_v_e <= i_v_d;
|
i_v_e <= i_v_d;
|
||||||
i_l_e <= i_l_d;
|
i_l_e <= i_l_d;
|
||||||
@ -472,16 +493,18 @@ generate if(READ_BUFFER) begin
|
|||||||
localparam AWIDTH = 10;
|
localparam AWIDTH = 10;
|
||||||
localparam DWIDTH = 1 + (8<<DQ_LEVEL);
|
localparam DWIDTH = 1 + (8<<DQ_LEVEL);
|
||||||
|
|
||||||
reg [AWIDTH-1:0] wpt = '0, rpt = '0;
|
reg [AWIDTH-1:0] wpt = 0, rpt = 0;
|
||||||
reg dvalid = '0, valid = '0;
|
reg dvalid = 1'b0, valid = 1'b0;
|
||||||
reg [DWIDTH-1:0] datareg = '0;
|
reg [DWIDTH-1:0] datareg = 0;
|
||||||
|
|
||||||
wire rreq;
|
wire rreq;
|
||||||
reg [DWIDTH-1:0] fifo_rdata;
|
reg [DWIDTH-1:0] fifo_rdata;
|
||||||
|
|
||||||
wire emptyn = rpt != wpt;
|
wire emptyn = rpt != wpt;
|
||||||
|
|
||||||
wire itready = rpt != (wpt + (AWIDTH)'(1));
|
localparam [AWIDTH-1:0] AW_ONE = 1;
|
||||||
|
|
||||||
|
wire itready = rpt != (wpt + AW_ONE);
|
||||||
assign rvalid = valid | dvalid;
|
assign rvalid = valid | dvalid;
|
||||||
assign rreq = emptyn & ( rready | ~rvalid );
|
assign rreq = emptyn & ( rready | ~rvalid );
|
||||||
assign {rlast, rdata} = dvalid ? fifo_rdata : datareg;
|
assign {rlast, rdata} = dvalid ? fifo_rdata : datareg;
|
||||||
@ -490,13 +513,13 @@ generate if(READ_BUFFER) begin
|
|||||||
if(~rstn)
|
if(~rstn)
|
||||||
wpt <= 0;
|
wpt <= 0;
|
||||||
else if(i_v_e & itready)
|
else if(i_v_e & itready)
|
||||||
wpt <= wpt + (AWIDTH)'(1);
|
wpt <= wpt + AW_ONE;
|
||||||
|
|
||||||
always @ (posedge clk or negedge rstn)
|
always @ (posedge clk or negedge rstn)
|
||||||
if(~rstn)
|
if(~rstn)
|
||||||
rpt <= 0;
|
rpt <= 0;
|
||||||
else if(rreq & emptyn)
|
else if(rreq & emptyn)
|
||||||
rpt <= rpt + (AWIDTH)'(1);
|
rpt <= rpt + AW_ONE;
|
||||||
|
|
||||||
always @ (posedge clk or negedge rstn)
|
always @ (posedge clk or negedge rstn)
|
||||||
if(~rstn) begin
|
if(~rstn) begin
|
@ -2,7 +2,7 @@
|
|||||||
//--------------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------------
|
||||||
// Module : axi_self_test_master
|
// Module : axi_self_test_master
|
||||||
// Type : synthesizable
|
// Type : synthesizable
|
||||||
// Standard: SystemVerilog 2005 (IEEE1800-2005)
|
// Standard: Verilog 2001 (IEEE1364-2001)
|
||||||
// Function: write increase data to AXI4 slave,
|
// Function: write increase data to AXI4 slave,
|
||||||
// then read data and check whether they are increasing
|
// then read data and check whether they are increasing
|
||||||
//--------------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------------
|
||||||
@ -39,13 +39,22 @@ module axi_self_test_master #(
|
|||||||
output reg [ 15:0] error_cnt
|
output reg [ 15:0] error_cnt
|
||||||
);
|
);
|
||||||
|
|
||||||
initial {awaddr, araddr} = '0;
|
|
||||||
initial {error, error_cnt} = '0;
|
initial {awaddr, araddr} = 0;
|
||||||
|
initial {error, error_cnt} = 0;
|
||||||
|
|
||||||
wire aw_end;
|
wire aw_end;
|
||||||
reg awaddr_carry = '0;
|
reg awaddr_carry = 1'b0;
|
||||||
reg [7:0] w_cnt = '0;
|
reg [7:0] w_cnt = 8'd0;
|
||||||
enum logic [2:0] {INIT, AW, W, B, AR, R} stat = INIT;
|
|
||||||
|
localparam [2:0] INIT = 3'd0,
|
||||||
|
AW = 3'd1,
|
||||||
|
W = 3'd2,
|
||||||
|
B = 3'd3,
|
||||||
|
AR = 3'd4,
|
||||||
|
R = 3'd5;
|
||||||
|
|
||||||
|
reg [2:0] stat = INIT;
|
||||||
|
|
||||||
generate if(A_WIDTH_TEST<A_WIDTH)
|
generate if(A_WIDTH_TEST<A_WIDTH)
|
||||||
assign aw_end = awaddr[A_WIDTH_TEST];
|
assign aw_end = awaddr[A_WIDTH_TEST];
|
||||||
@ -57,26 +66,27 @@ assign awvalid = stat==AW;
|
|||||||
assign awlen = WBURST_LEN;
|
assign awlen = WBURST_LEN;
|
||||||
assign wvalid = stat==W;
|
assign wvalid = stat==W;
|
||||||
assign wlast = w_cnt==WBURST_LEN;
|
assign wlast = w_cnt==WBURST_LEN;
|
||||||
assign wdata = (D_WIDTH)'(awaddr);
|
assign wdata = awaddr;
|
||||||
assign bready = 1'b1;
|
assign bready = 1'b1;
|
||||||
assign arvalid = stat==AR;
|
assign arvalid = stat==AR;
|
||||||
assign arlen = RBURST_LEN;
|
assign arlen = RBURST_LEN;
|
||||||
assign rready = 1'b1;
|
assign rready = 1'b1;
|
||||||
|
|
||||||
wire [A_WIDTH:0] araddr_next = {1'b0,araddr} + (A_WIDTH+1)'(1<<D_LEVEL);
|
localparam [A_WIDTH:0] ADDR_INC = (1<<D_LEVEL);
|
||||||
|
wire [A_WIDTH:0] araddr_next = {1'b0,araddr} + ADDR_INC;
|
||||||
|
|
||||||
always @ (posedge clk or negedge rstn)
|
always @ (posedge clk or negedge rstn)
|
||||||
if(~rstn) begin
|
if(~rstn) begin
|
||||||
{awaddr_carry, awaddr} <= '0;
|
{awaddr_carry, awaddr} <= 0;
|
||||||
w_cnt <= 8'd0;
|
w_cnt <= 8'd0;
|
||||||
araddr <= '0;
|
araddr <= 0;
|
||||||
stat <= INIT;
|
stat <= INIT;
|
||||||
end else begin
|
end else begin
|
||||||
case(stat)
|
case(stat)
|
||||||
INIT: begin
|
INIT: begin
|
||||||
{awaddr_carry, awaddr} <= '0;
|
{awaddr_carry, awaddr} <= 0;
|
||||||
w_cnt <= 8'd0;
|
w_cnt <= 8'd0;
|
||||||
araddr <= '0;
|
araddr <= 0;
|
||||||
stat <= AW;
|
stat <= AW;
|
||||||
end
|
end
|
||||||
AW: if(awready) begin
|
AW: if(awready) begin
|
||||||
@ -84,7 +94,7 @@ always @ (posedge clk or negedge rstn)
|
|||||||
stat <= W;
|
stat <= W;
|
||||||
end
|
end
|
||||||
W: if(wready) begin
|
W: if(wready) begin
|
||||||
{awaddr_carry, awaddr} <= {awaddr_carry, awaddr} + (A_WIDTH+1)'(1<<D_LEVEL);
|
{awaddr_carry, awaddr} <= {awaddr_carry, awaddr} + ADDR_INC;
|
||||||
w_cnt <= w_cnt + 8'd1;
|
w_cnt <= w_cnt + 8'd1;
|
||||||
if(wlast)
|
if(wlast)
|
||||||
stat <= B;
|
stat <= B;
|
||||||
@ -100,7 +110,7 @@ always @ (posedge clk or negedge rstn)
|
|||||||
if(rlast) begin
|
if(rlast) begin
|
||||||
stat <= AR;
|
stat <= AR;
|
||||||
if(araddr_next[A_WIDTH_TEST])
|
if(araddr_next[A_WIDTH_TEST])
|
||||||
araddr <= '0;
|
araddr <= 0;
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
endcase
|
endcase
|
||||||
@ -109,7 +119,8 @@ always @ (posedge clk or negedge rstn)
|
|||||||
// ------------------------------------------------------------
|
// ------------------------------------------------------------
|
||||||
// read and write mismatch detect
|
// read and write mismatch detect
|
||||||
// ------------------------------------------------------------
|
// ------------------------------------------------------------
|
||||||
wire [D_WIDTH-1:0] rdata_idle = (D_WIDTH)'(araddr);
|
wire [D_WIDTH-1:0] rdata_idle = araddr;
|
||||||
|
|
||||||
always @ (posedge clk or negedge rstn)
|
always @ (posedge clk or negedge rstn)
|
||||||
if(~rstn) begin
|
if(~rstn) begin
|
||||||
error <= 1'b0;
|
error <= 1'b0;
|
@ -2,7 +2,7 @@
|
|||||||
//--------------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------------
|
||||||
// Module : tb_ddr_sdram_ctrl
|
// Module : tb_ddr_sdram_ctrl
|
||||||
// Type : simulation, top
|
// Type : simulation, top
|
||||||
// Standard: SystemVerilog 2005 (IEEE1800-2005)
|
// Standard: Verilog 2001 (IEEE1364-2001)
|
||||||
// Function: testbench for ddr_sdram_ctrl
|
// Function: testbench for ddr_sdram_ctrl
|
||||||
//--------------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------------
|
||||||
|
|
@ -1,5 +1,5 @@
|
|||||||
del sim.out dump.vcd
|
del sim.out dump.vcd
|
||||||
iverilog -g2005-sv -o sim.out tb_ddr_sdram_ctrl.sv axi_self_test_master.sv micron_ddr_sdram_model.sv ../RTL/ddr_sdram_ctrl.sv
|
iverilog -g2001 -o sim.out tb_ddr_sdram_ctrl.v axi_self_test_master.v micron_ddr_sdram_model.v ../RTL/ddr_sdram_ctrl.v
|
||||||
vvp -n sim.out
|
vvp -n sim.out
|
||||||
del sim.out
|
del sim.out
|
||||||
pause
|
pause
|
File diff suppressed because one or more lines are too long
@ -2,7 +2,7 @@
|
|||||||
//--------------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------------
|
||||||
// Module : axi_self_test_master
|
// Module : axi_self_test_master
|
||||||
// Type : synthesizable
|
// Type : synthesizable
|
||||||
// Standard: SystemVerilog 2005 (IEEE1800-2005)
|
// Standard: Verilog 2001 (IEEE1364-2001)
|
||||||
// Function: write increase data to AXI4 slave,
|
// Function: write increase data to AXI4 slave,
|
||||||
// then read data and check whether they are increasing
|
// then read data and check whether they are increasing
|
||||||
//--------------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------------
|
||||||
@ -39,13 +39,22 @@ module axi_self_test_master #(
|
|||||||
output reg [ 15:0] error_cnt
|
output reg [ 15:0] error_cnt
|
||||||
);
|
);
|
||||||
|
|
||||||
initial {awaddr, araddr} = '0;
|
|
||||||
initial {error, error_cnt} = '0;
|
initial {awaddr, araddr} = 0;
|
||||||
|
initial {error, error_cnt} = 0;
|
||||||
|
|
||||||
wire aw_end;
|
wire aw_end;
|
||||||
reg awaddr_carry = '0;
|
reg awaddr_carry = 1'b0;
|
||||||
reg [7:0] w_cnt = '0;
|
reg [7:0] w_cnt = 8'd0;
|
||||||
enum logic [2:0] {INIT, AW, W, B, AR, R} stat = INIT;
|
|
||||||
|
localparam [2:0] INIT = 3'd0,
|
||||||
|
AW = 3'd1,
|
||||||
|
W = 3'd2,
|
||||||
|
B = 3'd3,
|
||||||
|
AR = 3'd4,
|
||||||
|
R = 3'd5;
|
||||||
|
|
||||||
|
reg [2:0] stat = INIT;
|
||||||
|
|
||||||
generate if(A_WIDTH_TEST<A_WIDTH)
|
generate if(A_WIDTH_TEST<A_WIDTH)
|
||||||
assign aw_end = awaddr[A_WIDTH_TEST];
|
assign aw_end = awaddr[A_WIDTH_TEST];
|
||||||
@ -57,26 +66,27 @@ assign awvalid = stat==AW;
|
|||||||
assign awlen = WBURST_LEN;
|
assign awlen = WBURST_LEN;
|
||||||
assign wvalid = stat==W;
|
assign wvalid = stat==W;
|
||||||
assign wlast = w_cnt==WBURST_LEN;
|
assign wlast = w_cnt==WBURST_LEN;
|
||||||
assign wdata = (D_WIDTH)'(awaddr);
|
assign wdata = awaddr;
|
||||||
assign bready = 1'b1;
|
assign bready = 1'b1;
|
||||||
assign arvalid = stat==AR;
|
assign arvalid = stat==AR;
|
||||||
assign arlen = RBURST_LEN;
|
assign arlen = RBURST_LEN;
|
||||||
assign rready = 1'b1;
|
assign rready = 1'b1;
|
||||||
|
|
||||||
wire [A_WIDTH:0] araddr_next = {1'b0,araddr} + (A_WIDTH+1)'(1<<D_LEVEL);
|
localparam [A_WIDTH:0] ADDR_INC = (1<<D_LEVEL);
|
||||||
|
wire [A_WIDTH:0] araddr_next = {1'b0,araddr} + ADDR_INC;
|
||||||
|
|
||||||
always @ (posedge clk or negedge rstn)
|
always @ (posedge clk or negedge rstn)
|
||||||
if(~rstn) begin
|
if(~rstn) begin
|
||||||
{awaddr_carry, awaddr} <= '0;
|
{awaddr_carry, awaddr} <= 0;
|
||||||
w_cnt <= 8'd0;
|
w_cnt <= 8'd0;
|
||||||
araddr <= '0;
|
araddr <= 0;
|
||||||
stat <= INIT;
|
stat <= INIT;
|
||||||
end else begin
|
end else begin
|
||||||
case(stat)
|
case(stat)
|
||||||
INIT: begin
|
INIT: begin
|
||||||
{awaddr_carry, awaddr} <= '0;
|
{awaddr_carry, awaddr} <= 0;
|
||||||
w_cnt <= 8'd0;
|
w_cnt <= 8'd0;
|
||||||
araddr <= '0;
|
araddr <= 0;
|
||||||
stat <= AW;
|
stat <= AW;
|
||||||
end
|
end
|
||||||
AW: if(awready) begin
|
AW: if(awready) begin
|
||||||
@ -84,7 +94,7 @@ always @ (posedge clk or negedge rstn)
|
|||||||
stat <= W;
|
stat <= W;
|
||||||
end
|
end
|
||||||
W: if(wready) begin
|
W: if(wready) begin
|
||||||
{awaddr_carry, awaddr} <= {awaddr_carry, awaddr} + (A_WIDTH+1)'(1<<D_LEVEL);
|
{awaddr_carry, awaddr} <= {awaddr_carry, awaddr} + ADDR_INC;
|
||||||
w_cnt <= w_cnt + 8'd1;
|
w_cnt <= w_cnt + 8'd1;
|
||||||
if(wlast)
|
if(wlast)
|
||||||
stat <= B;
|
stat <= B;
|
||||||
@ -100,7 +110,7 @@ always @ (posedge clk or negedge rstn)
|
|||||||
if(rlast) begin
|
if(rlast) begin
|
||||||
stat <= AR;
|
stat <= AR;
|
||||||
if(araddr_next[A_WIDTH_TEST])
|
if(araddr_next[A_WIDTH_TEST])
|
||||||
araddr <= '0;
|
araddr <= 0;
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
endcase
|
endcase
|
||||||
@ -109,7 +119,8 @@ always @ (posedge clk or negedge rstn)
|
|||||||
// ------------------------------------------------------------
|
// ------------------------------------------------------------
|
||||||
// read and write mismatch detect
|
// read and write mismatch detect
|
||||||
// ------------------------------------------------------------
|
// ------------------------------------------------------------
|
||||||
wire [D_WIDTH-1:0] rdata_idle = (D_WIDTH)'(araddr);
|
wire [D_WIDTH-1:0] rdata_idle = araddr;
|
||||||
|
|
||||||
always @ (posedge clk or negedge rstn)
|
always @ (posedge clk or negedge rstn)
|
||||||
if(~rstn) begin
|
if(~rstn) begin
|
||||||
error <= 1'b0;
|
error <= 1'b0;
|
@ -38,10 +38,10 @@
|
|||||||
|
|
||||||
set_global_assignment -name FAMILY "Cyclone IV E"
|
set_global_assignment -name FAMILY "Cyclone IV E"
|
||||||
set_global_assignment -name DEVICE EP4CE6E22C8
|
set_global_assignment -name DEVICE EP4CE6E22C8
|
||||||
set_global_assignment -name TOP_LEVEL_ENTITY top
|
set_global_assignment -name TOP_LEVEL_ENTITY fpga_top
|
||||||
set_global_assignment -name ORIGINAL_QUARTUS_VERSION 13.1
|
set_global_assignment -name ORIGINAL_QUARTUS_VERSION 13.1
|
||||||
set_global_assignment -name PROJECT_CREATION_TIME_DATE "21:02:52 JANUARY 17, 2021"
|
set_global_assignment -name PROJECT_CREATION_TIME_DATE "21:02:52 JANUARY 17, 2021"
|
||||||
set_global_assignment -name LAST_QUARTUS_VERSION "18.1.0 Standard Edition"
|
set_global_assignment -name LAST_QUARTUS_VERSION 13.1
|
||||||
set_global_assignment -name PROJECT_OUTPUT_DIRECTORY output_files
|
set_global_assignment -name PROJECT_OUTPUT_DIRECTORY output_files
|
||||||
set_global_assignment -name MIN_CORE_JUNCTION_TEMP 0
|
set_global_assignment -name MIN_CORE_JUNCTION_TEMP 0
|
||||||
set_global_assignment -name MAX_CORE_JUNCTION_TEMP 85
|
set_global_assignment -name MAX_CORE_JUNCTION_TEMP 85
|
||||||
@ -102,9 +102,6 @@ set_location_assignment PIN_121 -to error_cnt[13]
|
|||||||
set_location_assignment PIN_120 -to error_cnt[14]
|
set_location_assignment PIN_120 -to error_cnt[14]
|
||||||
set_location_assignment PIN_119 -to error_cnt[15]
|
set_location_assignment PIN_119 -to error_cnt[15]
|
||||||
|
|
||||||
set_global_assignment -name PARTITION_NETLIST_TYPE SOURCE -section_id Top
|
|
||||||
set_global_assignment -name PARTITION_FITTER_PRESERVATION_LEVEL PLACEMENT_AND_ROUTING -section_id Top
|
|
||||||
set_global_assignment -name PARTITION_COLOR 16764057 -section_id Top
|
|
||||||
set_global_assignment -name ENABLE_SIGNALTAP ON
|
set_global_assignment -name ENABLE_SIGNALTAP ON
|
||||||
set_global_assignment -name USE_SIGNALTAP_FILE SignalTap/stp1.stp
|
set_global_assignment -name USE_SIGNALTAP_FILE SignalTap/stp1.stp
|
||||||
set_global_assignment -name SLD_NODE_CREATOR_ID 110 -section_id auto_signaltap_0
|
set_global_assignment -name SLD_NODE_CREATOR_ID 110 -section_id auto_signaltap_0
|
||||||
@ -130,9 +127,9 @@ set_global_assignment -name SLD_NODE_PARAMETER_ASSIGNMENT "SLD_TRIGGER_LEVEL_PIP
|
|||||||
set_global_assignment -name SLD_NODE_PARAMETER_ASSIGNMENT "SLD_ENABLE_ADVANCED_TRIGGER=0" -section_id auto_signaltap_0
|
set_global_assignment -name SLD_NODE_PARAMETER_ASSIGNMENT "SLD_ENABLE_ADVANCED_TRIGGER=0" -section_id auto_signaltap_0
|
||||||
set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_clk -to "ddr_ctrl:ddr_ctrl_i|clk2" -section_id auto_signaltap_0
|
set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_clk -to "ddr_ctrl:ddr_ctrl_i|clk2" -section_id auto_signaltap_0
|
||||||
|
|
||||||
set_global_assignment -name SYSTEMVERILOG_FILE top.sv
|
set_global_assignment -name VERILOG_FILE fpga_top.v
|
||||||
set_global_assignment -name SYSTEMVERILOG_FILE axi_self_test_master.sv
|
set_global_assignment -name VERILOG_FILE axi_self_test_master.v
|
||||||
set_global_assignment -name SYSTEMVERILOG_FILE ../RTL/ddr_sdram_ctrl.sv
|
set_global_assignment -name VERILOG_FILE ../RTL/ddr_sdram_ctrl.v
|
||||||
set_global_assignment -name SIGNALTAP_FILE SignalTap/stp1.stp
|
set_global_assignment -name SIGNALTAP_FILE SignalTap/stp1.stp
|
||||||
|
|
||||||
set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[0] -to error -section_id auto_signaltap_0
|
set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[0] -to error -section_id auto_signaltap_0
|
||||||
@ -174,42 +171,11 @@ set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[34] -t
|
|||||||
set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[35] -to error_cnt[8] -section_id auto_signaltap_0
|
set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[35] -to error_cnt[8] -section_id auto_signaltap_0
|
||||||
set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[36] -to error_cnt[9] -section_id auto_signaltap_0
|
set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[36] -to error_cnt[9] -section_id auto_signaltap_0
|
||||||
set_global_assignment -name SLD_NODE_PARAMETER_ASSIGNMENT "SLD_DATA_BITS=37" -section_id auto_signaltap_0
|
set_global_assignment -name SLD_NODE_PARAMETER_ASSIGNMENT "SLD_DATA_BITS=37" -section_id auto_signaltap_0
|
||||||
set_global_assignment -name SLD_NODE_PARAMETER_ASSIGNMENT "SLD_STORAGE_QUALIFIER_BITS=47" -section_id auto_signaltap_0
|
|
||||||
set_global_assignment -name SLD_NODE_PARAMETER_ASSIGNMENT "SLD_INCREMENTAL_ROUTING=1" -section_id auto_signaltap_0
|
set_global_assignment -name SLD_NODE_PARAMETER_ASSIGNMENT "SLD_NODE_CRC_LOWORD=45013" -section_id auto_signaltap_0
|
||||||
set_instance_assignment -name POST_FIT_CONNECT_TO_SLD_NODE_ENTITY_PORT crc[0] -to auto_signaltap_0|vcc -section_id auto_signaltap_0
|
set_global_assignment -name SLD_NODE_PARAMETER_ASSIGNMENT "SLD_NODE_CRC_HIWORD=22477" -section_id auto_signaltap_0
|
||||||
set_instance_assignment -name POST_FIT_CONNECT_TO_SLD_NODE_ENTITY_PORT crc[1] -to auto_signaltap_0|gnd -section_id auto_signaltap_0
|
set_global_assignment -name PARTITION_NETLIST_TYPE SOURCE -section_id Top
|
||||||
set_instance_assignment -name POST_FIT_CONNECT_TO_SLD_NODE_ENTITY_PORT crc[2] -to auto_signaltap_0|vcc -section_id auto_signaltap_0
|
set_global_assignment -name PARTITION_FITTER_PRESERVATION_LEVEL PLACEMENT_AND_ROUTING -section_id Top
|
||||||
set_instance_assignment -name POST_FIT_CONNECT_TO_SLD_NODE_ENTITY_PORT crc[3] -to auto_signaltap_0|gnd -section_id auto_signaltap_0
|
set_global_assignment -name PARTITION_COLOR 16764057 -section_id Top
|
||||||
set_instance_assignment -name POST_FIT_CONNECT_TO_SLD_NODE_ENTITY_PORT crc[4] -to auto_signaltap_0|vcc -section_id auto_signaltap_0
|
|
||||||
set_instance_assignment -name POST_FIT_CONNECT_TO_SLD_NODE_ENTITY_PORT crc[5] -to auto_signaltap_0|gnd -section_id auto_signaltap_0
|
|
||||||
set_instance_assignment -name POST_FIT_CONNECT_TO_SLD_NODE_ENTITY_PORT crc[6] -to auto_signaltap_0|vcc -section_id auto_signaltap_0
|
|
||||||
set_instance_assignment -name POST_FIT_CONNECT_TO_SLD_NODE_ENTITY_PORT crc[7] -to auto_signaltap_0|vcc -section_id auto_signaltap_0
|
|
||||||
set_instance_assignment -name POST_FIT_CONNECT_TO_SLD_NODE_ENTITY_PORT crc[8] -to auto_signaltap_0|vcc -section_id auto_signaltap_0
|
|
||||||
set_instance_assignment -name POST_FIT_CONNECT_TO_SLD_NODE_ENTITY_PORT crc[9] -to auto_signaltap_0|vcc -section_id auto_signaltap_0
|
|
||||||
set_instance_assignment -name POST_FIT_CONNECT_TO_SLD_NODE_ENTITY_PORT crc[10] -to auto_signaltap_0|vcc -section_id auto_signaltap_0
|
|
||||||
set_instance_assignment -name POST_FIT_CONNECT_TO_SLD_NODE_ENTITY_PORT crc[11] -to auto_signaltap_0|vcc -section_id auto_signaltap_0
|
|
||||||
set_instance_assignment -name POST_FIT_CONNECT_TO_SLD_NODE_ENTITY_PORT crc[12] -to auto_signaltap_0|gnd -section_id auto_signaltap_0
|
|
||||||
set_instance_assignment -name POST_FIT_CONNECT_TO_SLD_NODE_ENTITY_PORT crc[13] -to auto_signaltap_0|vcc -section_id auto_signaltap_0
|
|
||||||
set_instance_assignment -name POST_FIT_CONNECT_TO_SLD_NODE_ENTITY_PORT crc[14] -to auto_signaltap_0|gnd -section_id auto_signaltap_0
|
|
||||||
set_instance_assignment -name POST_FIT_CONNECT_TO_SLD_NODE_ENTITY_PORT crc[15] -to auto_signaltap_0|vcc -section_id auto_signaltap_0
|
|
||||||
set_instance_assignment -name POST_FIT_CONNECT_TO_SLD_NODE_ENTITY_PORT crc[16] -to auto_signaltap_0|vcc -section_id auto_signaltap_0
|
|
||||||
set_instance_assignment -name POST_FIT_CONNECT_TO_SLD_NODE_ENTITY_PORT crc[17] -to auto_signaltap_0|gnd -section_id auto_signaltap_0
|
|
||||||
set_instance_assignment -name POST_FIT_CONNECT_TO_SLD_NODE_ENTITY_PORT crc[18] -to auto_signaltap_0|vcc -section_id auto_signaltap_0
|
|
||||||
set_instance_assignment -name POST_FIT_CONNECT_TO_SLD_NODE_ENTITY_PORT crc[19] -to auto_signaltap_0|vcc -section_id auto_signaltap_0
|
|
||||||
set_instance_assignment -name POST_FIT_CONNECT_TO_SLD_NODE_ENTITY_PORT crc[20] -to auto_signaltap_0|gnd -section_id auto_signaltap_0
|
|
||||||
set_instance_assignment -name POST_FIT_CONNECT_TO_SLD_NODE_ENTITY_PORT crc[21] -to auto_signaltap_0|gnd -section_id auto_signaltap_0
|
|
||||||
set_instance_assignment -name POST_FIT_CONNECT_TO_SLD_NODE_ENTITY_PORT crc[22] -to auto_signaltap_0|vcc -section_id auto_signaltap_0
|
|
||||||
set_instance_assignment -name POST_FIT_CONNECT_TO_SLD_NODE_ENTITY_PORT crc[23] -to auto_signaltap_0|vcc -section_id auto_signaltap_0
|
|
||||||
set_instance_assignment -name POST_FIT_CONNECT_TO_SLD_NODE_ENTITY_PORT crc[24] -to auto_signaltap_0|vcc -section_id auto_signaltap_0
|
|
||||||
set_instance_assignment -name POST_FIT_CONNECT_TO_SLD_NODE_ENTITY_PORT crc[25] -to auto_signaltap_0|vcc -section_id auto_signaltap_0
|
|
||||||
set_instance_assignment -name POST_FIT_CONNECT_TO_SLD_NODE_ENTITY_PORT crc[26] -to auto_signaltap_0|vcc -section_id auto_signaltap_0
|
|
||||||
set_instance_assignment -name POST_FIT_CONNECT_TO_SLD_NODE_ENTITY_PORT crc[27] -to auto_signaltap_0|gnd -section_id auto_signaltap_0
|
|
||||||
set_instance_assignment -name POST_FIT_CONNECT_TO_SLD_NODE_ENTITY_PORT crc[28] -to auto_signaltap_0|vcc -section_id auto_signaltap_0
|
|
||||||
set_instance_assignment -name POST_FIT_CONNECT_TO_SLD_NODE_ENTITY_PORT crc[29] -to auto_signaltap_0|gnd -section_id auto_signaltap_0
|
|
||||||
set_instance_assignment -name POST_FIT_CONNECT_TO_SLD_NODE_ENTITY_PORT crc[30] -to auto_signaltap_0|vcc -section_id auto_signaltap_0
|
|
||||||
set_instance_assignment -name POST_FIT_CONNECT_TO_SLD_NODE_ENTITY_PORT crc[31] -to auto_signaltap_0|gnd -section_id auto_signaltap_0
|
|
||||||
set_global_assignment -name SLD_NODE_PARAMETER_ASSIGNMENT "SLD_TRIGGER_PIPELINE=0" -section_id auto_signaltap_0
|
|
||||||
set_global_assignment -name SLD_NODE_PARAMETER_ASSIGNMENT "SLD_RAM_PIPELINE=0" -section_id auto_signaltap_0
|
|
||||||
set_global_assignment -name SLD_NODE_PARAMETER_ASSIGNMENT "SLD_COUNTER_PIPELINE=0" -section_id auto_signaltap_0
|
|
||||||
set_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top
|
|
||||||
set_global_assignment -name SLD_FILE db/stp1_auto_stripped.stp
|
set_global_assignment -name SLD_FILE db/stp1_auto_stripped.stp
|
||||||
|
set_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top
|
@ -1,14 +1,14 @@
|
|||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------------
|
||||||
// Module : top
|
// Module : fpga_top
|
||||||
// Type : synthesizable, FPGA's top, IP's example design
|
// Type : synthesizable, FPGA's top, IP's example design
|
||||||
// Standard: SystemVerilog 2005 (IEEE1800-2005)
|
// Standard: Verilog 2001 (IEEE1364-2001)
|
||||||
// Function: an example of ddr_sdram_ctrl,
|
// Function: an example of ddr_sdram_ctrl,
|
||||||
// write increase data to DDR,
|
// write increase data to DDR,
|
||||||
// then read data and check whether they are increasing
|
// then read data and check whether they are increasing
|
||||||
//--------------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
module top (
|
module fpga_top (
|
||||||
input wire clk50m,
|
input wire clk50m,
|
||||||
|
|
||||||
output wire ddr_ck_p, ddr_ck_n,
|
output wire ddr_ck_p, ddr_ck_n,
|
@ -38,10 +38,10 @@
|
|||||||
|
|
||||||
set_global_assignment -name FAMILY "Cyclone IV E"
|
set_global_assignment -name FAMILY "Cyclone IV E"
|
||||||
set_global_assignment -name DEVICE EP4CE6E22C8
|
set_global_assignment -name DEVICE EP4CE6E22C8
|
||||||
set_global_assignment -name TOP_LEVEL_ENTITY top
|
set_global_assignment -name TOP_LEVEL_ENTITY fpga_top
|
||||||
set_global_assignment -name ORIGINAL_QUARTUS_VERSION 13.1
|
set_global_assignment -name ORIGINAL_QUARTUS_VERSION 13.1
|
||||||
set_global_assignment -name PROJECT_CREATION_TIME_DATE "17:45:24 JANUARY 23, 2021"
|
set_global_assignment -name PROJECT_CREATION_TIME_DATE "17:45:24 JANUARY 23, 2021"
|
||||||
set_global_assignment -name LAST_QUARTUS_VERSION "18.1.0 Standard Edition"
|
set_global_assignment -name LAST_QUARTUS_VERSION 13.1
|
||||||
set_global_assignment -name PROJECT_OUTPUT_DIRECTORY output_files
|
set_global_assignment -name PROJECT_OUTPUT_DIRECTORY output_files
|
||||||
set_global_assignment -name MIN_CORE_JUNCTION_TEMP 0
|
set_global_assignment -name MIN_CORE_JUNCTION_TEMP 0
|
||||||
set_global_assignment -name MAX_CORE_JUNCTION_TEMP 85
|
set_global_assignment -name MAX_CORE_JUNCTION_TEMP 85
|
||||||
@ -49,9 +49,11 @@ set_global_assignment -name ERROR_CHECK_FREQUENCY_DIVISOR 1
|
|||||||
set_global_assignment -name NOMINAL_CORE_SUPPLY_VOLTAGE 1.2V
|
set_global_assignment -name NOMINAL_CORE_SUPPLY_VOLTAGE 1.2V
|
||||||
set_global_assignment -name STRATIX_DEVICE_IO_STANDARD "2.5 V"
|
set_global_assignment -name STRATIX_DEVICE_IO_STANDARD "2.5 V"
|
||||||
|
|
||||||
set_global_assignment -name SYSTEMVERILOG_FILE top.sv
|
set_global_assignment -name VERILOG_FILE fpga_top.v
|
||||||
set_global_assignment -name SYSTEMVERILOG_FILE uart2axi4.sv
|
set_global_assignment -name VERILOG_FILE uart/uart2axi4.v
|
||||||
set_global_assignment -name SYSTEMVERILOG_FILE ../RTL/ddr_sdram_ctrl.sv
|
set_global_assignment -name VERILOG_FILE uart/uart_rx.v
|
||||||
|
set_global_assignment -name VERILOG_FILE uart/uart_tx.v
|
||||||
|
set_global_assignment -name VERILOG_FILE ../RTL/ddr_sdram_ctrl.v
|
||||||
|
|
||||||
set_location_assignment PIN_23 -to clk50m
|
set_location_assignment PIN_23 -to clk50m
|
||||||
|
|
||||||
@ -92,7 +94,8 @@ set_location_assignment PIN_74 -to ddr_dq[6]
|
|||||||
set_location_assignment PIN_73 -to ddr_dq[7]
|
set_location_assignment PIN_73 -to ddr_dq[7]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
set_global_assignment -name PARTITION_NETLIST_TYPE SOURCE -section_id Top
|
set_global_assignment -name PARTITION_NETLIST_TYPE SOURCE -section_id Top
|
||||||
set_global_assignment -name PARTITION_FITTER_PRESERVATION_LEVEL PLACEMENT_AND_ROUTING -section_id Top
|
set_global_assignment -name PARTITION_FITTER_PRESERVATION_LEVEL PLACEMENT_AND_ROUTING -section_id Top
|
||||||
set_global_assignment -name PARTITION_COLOR 16764057 -section_id Top
|
set_global_assignment -name PARTITION_COLOR 16764057 -section_id Top
|
||||||
set_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top
|
set_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top
|
@ -1,13 +1,13 @@
|
|||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------------
|
||||||
// Module : top
|
// Module : fpga_top
|
||||||
// Type : synthesizable, FPGA's top, IP's example design
|
// Type : synthesizable, FPGA's top, IP's example design
|
||||||
// Standard: SystemVerilog 2005 (IEEE1800-2005)
|
// Standard: Verilog 2001 (IEEE1364-2001)
|
||||||
// Function: an example of ddr_sdram_ctrl,
|
// Function: an example of ddr_sdram_ctrl,
|
||||||
// use UART command to read/write DDR
|
// use UART command to read/write DDR
|
||||||
//--------------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
module top (
|
module fpga_top (
|
||||||
input wire clk50m,
|
input wire clk50m,
|
||||||
|
|
||||||
output wire uart_tx,
|
output wire uart_tx,
|
||||||
@ -23,6 +23,7 @@ module top (
|
|||||||
inout [ 7:0] ddr_dq
|
inout [ 7:0] ddr_dq
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------------
|
||||||
// DDR-SDRAM parameters
|
// DDR-SDRAM parameters
|
||||||
// -------------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------------
|
||||||
@ -82,10 +83,15 @@ defparam altpll_i.bandwidth_type = "AUTO", altpll_i.clk0_divide_by = 1, altpl
|
|||||||
// AXI4 master for testing
|
// AXI4 master for testing
|
||||||
// -------------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------------
|
||||||
uart2axi4 #(
|
uart2axi4 #(
|
||||||
|
.CLK_FREQ ( 75000000 ), // clk is 75MHz
|
||||||
|
.BAUD_RATE ( 115200 ), // UART baud rate = 115200
|
||||||
|
.PARITY ( "NONE" ), // no parity
|
||||||
|
.BYTE_WIDTH ( D_WIDTH / 8 ),
|
||||||
.A_WIDTH ( A_WIDTH )
|
.A_WIDTH ( A_WIDTH )
|
||||||
) uart_axi_i (
|
) u_uart2axi4 (
|
||||||
.rstn ( rstn ),
|
.rstn ( rstn ),
|
||||||
.clk ( clk ),
|
.clk ( clk ),
|
||||||
|
// AXI4 master ----------------------
|
||||||
.awvalid ( awvalid ),
|
.awvalid ( awvalid ),
|
||||||
.awready ( awready ),
|
.awready ( awready ),
|
||||||
.awaddr ( awaddr ),
|
.awaddr ( awaddr ),
|
||||||
@ -104,8 +110,9 @@ uart2axi4 #(
|
|||||||
.rready ( rready ),
|
.rready ( rready ),
|
||||||
.rlast ( rlast ),
|
.rlast ( rlast ),
|
||||||
.rdata ( rdata ),
|
.rdata ( rdata ),
|
||||||
.uart_tx ( uart_tx ),
|
// UART ----------------------
|
||||||
.uart_rx ( uart_rx )
|
.i_uart_rx ( uart_rx ),
|
||||||
|
.o_uart_tx ( uart_tx )
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
@ -121,7 +128,7 @@ ddr_sdram_ctrl #(
|
|||||||
.tREFC ( 10'd512 ),
|
.tREFC ( 10'd512 ),
|
||||||
.tW2I ( 8'd7 ),
|
.tW2I ( 8'd7 ),
|
||||||
.tR2I ( 8'd7 )
|
.tR2I ( 8'd7 )
|
||||||
) ddr_ctrl_i(
|
) u_ddr_ctrl (
|
||||||
.rstn_async ( locked ),
|
.rstn_async ( locked ),
|
||||||
.drv_clk ( clk300m ),
|
.drv_clk ( clk300m ),
|
||||||
.rstn ( rstn ),
|
.rstn ( rstn ),
|
295
example-uart-read-write/uart/uart2axi4.v
Normal file
295
example-uart-read-write/uart/uart2axi4.v
Normal file
@ -0,0 +1,295 @@
|
|||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------------
|
||||||
|
// Module : uart2axi4
|
||||||
|
// Type : synthesizable
|
||||||
|
// Standard: Verilog 2001 (IEEE1364-2001)
|
||||||
|
// Function: convert UART command to AXI4 read/write action
|
||||||
|
//--------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
module uart2axi4 #(
|
||||||
|
// clock frequency
|
||||||
|
parameter CLK_FREQ = 50000000, // clk frequency, Unit : Hz
|
||||||
|
// UART format
|
||||||
|
parameter BAUD_RATE = 115200, // Unit : Hz
|
||||||
|
parameter PARITY = "NONE", // "NONE", "ODD", or "EVEN"
|
||||||
|
// AXI4 config
|
||||||
|
parameter BYTE_WIDTH = 2, // data width (bytes)
|
||||||
|
parameter A_WIDTH = 32 // address width (bits)
|
||||||
|
) (
|
||||||
|
input wire rstn,
|
||||||
|
input wire clk,
|
||||||
|
// AXI4 master ----------------------
|
||||||
|
input wire awready, // AW
|
||||||
|
output wire awvalid,
|
||||||
|
output wire [A_WIDTH-1:0] awaddr,
|
||||||
|
output wire [ 7:0] awlen,
|
||||||
|
input wire wready, // W
|
||||||
|
output wire wvalid,
|
||||||
|
output wire wlast,
|
||||||
|
output wire [8*BYTE_WIDTH-1:0] wdata,
|
||||||
|
output wire bready, // B
|
||||||
|
input wire bvalid,
|
||||||
|
input wire arready, // AR
|
||||||
|
output wire arvalid,
|
||||||
|
output wire [A_WIDTH-1:0] araddr,
|
||||||
|
output wire [ 7:0] arlen,
|
||||||
|
output wire rready, // R
|
||||||
|
input wire rvalid,
|
||||||
|
input wire rlast,
|
||||||
|
input wire [8*BYTE_WIDTH-1:0] rdata,
|
||||||
|
// UART ----------------------
|
||||||
|
input wire i_uart_rx,
|
||||||
|
output wire o_uart_tx
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
wire rx_valid;
|
||||||
|
wire [ 7:0] rx_byte;
|
||||||
|
|
||||||
|
uart_rx #(
|
||||||
|
.CLK_FREQ ( CLK_FREQ ),
|
||||||
|
.BAUD_RATE ( BAUD_RATE ),
|
||||||
|
.PARITY ( PARITY ),
|
||||||
|
.FIFO_EA ( 0 )
|
||||||
|
) u_uart_rx (
|
||||||
|
.rstn ( rstn ),
|
||||||
|
.clk ( clk ),
|
||||||
|
.i_uart_rx ( i_uart_rx ),
|
||||||
|
.o_tready ( 1'b1 ),
|
||||||
|
.o_tvalid ( rx_valid ),
|
||||||
|
.o_tdata ( rx_byte ),
|
||||||
|
.o_overflow ( )
|
||||||
|
);
|
||||||
|
|
||||||
|
wire rx_space = (rx_valid && (rx_byte == 8'h20)); // " "
|
||||||
|
wire rx_newline = (rx_valid && (rx_byte == 8'h0D || rx_byte == 8'h0A)); // \r, \n
|
||||||
|
wire rx_char_w = (rx_valid && (rx_byte == 8'h57 || rx_byte == 8'h77)); // W, w
|
||||||
|
wire rx_char_r = (rx_valid && (rx_byte == 8'h52 || rx_byte == 8'h72)); // R, r
|
||||||
|
wire rx_is_hex = (rx_valid && ((rx_byte>=8'h30 && rx_byte<=8'h39) || (rx_byte>=8'h41 && rx_byte<=8'h46) || (rx_byte>=8'h61 && rx_byte<=8'h66))); // 0~9, A~F, a~f
|
||||||
|
wire [ 3:0] rx_hex = (rx_byte>=8'h30 && rx_byte<=8'h39) ? rx_byte[3:0] : (rx_byte[3:0] + 4'd9);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
reg rwtype = 1'b0;
|
||||||
|
reg [A_WIDTH-1:0] addr = 0;
|
||||||
|
reg [ 8:0] len = 9'h0;
|
||||||
|
reg wwen = 1'b0;
|
||||||
|
reg [8*BYTE_WIDTH-1:0] wwdata = 0;
|
||||||
|
reg [ 7:0] wraddr = 8'h0;
|
||||||
|
|
||||||
|
|
||||||
|
localparam [ 3:0] S_IDLE = 4'd0,
|
||||||
|
S_PARSE_ADDR = 4'd1,
|
||||||
|
S_PARSE_LEN = 4'd2,
|
||||||
|
S_PARSE_WDATA = 4'd3,
|
||||||
|
S_AXI_RADDR = 4'd4,
|
||||||
|
S_AXI_WADDR = 4'd5,
|
||||||
|
S_AXI_RDATA = 4'd6,
|
||||||
|
S_AXI_WDATA = 4'd7,
|
||||||
|
S_AXI_B = 4'd8,
|
||||||
|
S_W_DONE = 4'd9,
|
||||||
|
S_INVALID = 4'd10,
|
||||||
|
S_FAILED = 4'd11;
|
||||||
|
|
||||||
|
reg [ 3:0] state = S_IDLE;
|
||||||
|
|
||||||
|
|
||||||
|
always @ (posedge clk or negedge rstn)
|
||||||
|
if (~rstn) begin
|
||||||
|
rwtype <= 1'b0;
|
||||||
|
addr <= 0;
|
||||||
|
len <= 9'h0;
|
||||||
|
wwen <= 1'b0;
|
||||||
|
wwdata <= 0;
|
||||||
|
wraddr <= 8'h0;
|
||||||
|
state <= S_IDLE;
|
||||||
|
end else begin
|
||||||
|
case (state)
|
||||||
|
|
||||||
|
S_IDLE : begin
|
||||||
|
rwtype <= rx_char_w;
|
||||||
|
addr <= 0;
|
||||||
|
len <= 9'h0;
|
||||||
|
wwen <= 1'b0;
|
||||||
|
wwdata <= 0;
|
||||||
|
wraddr <= 8'h0;
|
||||||
|
if (rx_char_w | rx_char_r)
|
||||||
|
state <= S_PARSE_ADDR;
|
||||||
|
else if (rx_space | rx_newline)
|
||||||
|
state <= S_IDLE;
|
||||||
|
else if (rx_valid)
|
||||||
|
state <= S_INVALID;
|
||||||
|
end
|
||||||
|
|
||||||
|
S_PARSE_ADDR :
|
||||||
|
if (rx_is_hex) begin
|
||||||
|
addr <= (addr << 4);
|
||||||
|
addr[3:0] <= rx_hex;
|
||||||
|
end else if (rx_space)
|
||||||
|
state <= rwtype ? S_PARSE_WDATA : S_PARSE_LEN;
|
||||||
|
else if (rx_newline)
|
||||||
|
state <= S_FAILED;
|
||||||
|
else if (rx_valid)
|
||||||
|
state <= S_INVALID;
|
||||||
|
|
||||||
|
S_PARSE_LEN :
|
||||||
|
if (rx_is_hex) begin
|
||||||
|
len <= (len << 4);
|
||||||
|
len[3:0] <= rx_hex;
|
||||||
|
end else if (rx_newline) begin
|
||||||
|
len <= (len >= 9'h100) ? 9'hFF : (len == 9'h0) ? 9'h0 : (len - 9'h1);
|
||||||
|
state <= S_AXI_RADDR;
|
||||||
|
end else if (rx_space) begin
|
||||||
|
state <= S_PARSE_LEN;
|
||||||
|
end else if (rx_valid) begin
|
||||||
|
state <= S_INVALID;
|
||||||
|
end
|
||||||
|
|
||||||
|
S_PARSE_WDATA :
|
||||||
|
if (rx_is_hex) begin
|
||||||
|
wwen <= 1'b1;
|
||||||
|
wwdata <= (wwdata << 4);
|
||||||
|
wwdata[3:0] <= rx_hex;
|
||||||
|
end else if (rx_space) begin
|
||||||
|
wwen <= 1'b0;
|
||||||
|
if (wwen) begin
|
||||||
|
wwdata <= 0;
|
||||||
|
len <= len + 9'd1;
|
||||||
|
end
|
||||||
|
end else if (rx_newline) begin
|
||||||
|
if (wwen) begin
|
||||||
|
state <= ( len < 9'h100) ? S_AXI_WADDR : S_FAILED;
|
||||||
|
end else begin
|
||||||
|
state <= (len >= 9'd0 && len <= 9'd100) ? S_AXI_WADDR : S_FAILED;
|
||||||
|
len <= len - 9'd1;
|
||||||
|
end
|
||||||
|
end else if (rx_valid) begin
|
||||||
|
state <= S_INVALID;
|
||||||
|
end
|
||||||
|
|
||||||
|
S_AXI_RADDR :
|
||||||
|
if (arready)
|
||||||
|
state <= S_AXI_RDATA;
|
||||||
|
|
||||||
|
S_AXI_WADDR :
|
||||||
|
if (awready)
|
||||||
|
state <= S_AXI_WDATA;
|
||||||
|
|
||||||
|
S_AXI_RDATA :
|
||||||
|
if (rvalid) begin
|
||||||
|
len <= len - 9'd1;
|
||||||
|
if (rlast || (len==9'd0))
|
||||||
|
state <= S_IDLE;
|
||||||
|
end
|
||||||
|
|
||||||
|
S_AXI_WDATA :
|
||||||
|
if (wready) begin
|
||||||
|
wraddr <= wraddr + 8'd1;
|
||||||
|
if (wraddr >= len[7:0])
|
||||||
|
state <= S_AXI_B;
|
||||||
|
end
|
||||||
|
|
||||||
|
S_AXI_B :
|
||||||
|
if (bvalid)
|
||||||
|
state <= S_W_DONE;
|
||||||
|
|
||||||
|
S_W_DONE :
|
||||||
|
state <= S_IDLE;
|
||||||
|
|
||||||
|
S_INVALID :
|
||||||
|
if (rx_newline)
|
||||||
|
state <= S_FAILED;
|
||||||
|
|
||||||
|
default : // S_FAILED :
|
||||||
|
state <= S_IDLE;
|
||||||
|
|
||||||
|
endcase
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
reg [8*BYTE_WIDTH-1:0] wbuf [0:255];
|
||||||
|
|
||||||
|
always @ (posedge clk)
|
||||||
|
if ( (state == S_PARSE_WDATA) && (rx_space || rx_newline) && wwen )
|
||||||
|
wbuf[len[7:0]] <= wwdata;
|
||||||
|
|
||||||
|
wire [ 7:0] wraddr_next = (wvalid & wready) ? (wraddr + 8'd1) : wraddr;
|
||||||
|
reg [8*BYTE_WIDTH-1:0] wrdata;
|
||||||
|
|
||||||
|
always @ (posedge clk)
|
||||||
|
wrdata <= wbuf[wraddr_next];
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
assign arvalid = (state == S_AXI_RADDR);
|
||||||
|
assign araddr = addr;
|
||||||
|
assign arlen = len[7:0];
|
||||||
|
|
||||||
|
assign awvalid = (state == S_AXI_WADDR);
|
||||||
|
assign awaddr = addr;
|
||||||
|
assign awlen = len[7:0];
|
||||||
|
|
||||||
|
assign rready = (state == S_AXI_RDATA);
|
||||||
|
|
||||||
|
assign wvalid = (state == S_AXI_WDATA);
|
||||||
|
assign wlast = (wraddr >= len[7:0]);
|
||||||
|
assign wdata = wrdata;
|
||||||
|
|
||||||
|
assign bready = 1'b1; // (state == S_AXI_B)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function [7:0] toHex;
|
||||||
|
input [3:0] val;
|
||||||
|
begin
|
||||||
|
toHex = (val <= 4'd9) ? {4'h3, val} : {4'd6, 1'b0, val[2:0]-3'h1};
|
||||||
|
end
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
|
||||||
|
wire tx_w_done = (state == S_W_DONE);
|
||||||
|
wire tx_failed = (state == S_FAILED);
|
||||||
|
wire tx_number = (rvalid & rready);
|
||||||
|
|
||||||
|
wire [8*2*BYTE_WIDTH-1:0] tx_data_failed = 64'h20_64_69_6C_61_76_6E_69; // "invalid"
|
||||||
|
wire [8*2*BYTE_WIDTH-1:0] tx_data_w_done = 64'h20_20_20_20_79_61_6B_6F; // "okay"
|
||||||
|
wire [8*2*BYTE_WIDTH-1:0] tx_data_number;
|
||||||
|
|
||||||
|
wire tx_valid = tx_failed | tx_w_done | tx_number;
|
||||||
|
wire [8*2*BYTE_WIDTH-1:0] tx_data = tx_failed ? tx_data_failed : tx_w_done ? tx_data_w_done : tx_data_number;
|
||||||
|
wire tx_last = tx_failed ? 1'b1 : tx_w_done ? 1'b1 : (rlast || (len==9'd0));
|
||||||
|
|
||||||
|
|
||||||
|
generate genvar i;
|
||||||
|
for (i=0; i<2*BYTE_WIDTH; i=i+1) begin : gen_tx_tdata
|
||||||
|
assign tx_data_number[8*i +: 8] = toHex(rdata[4*(2*BYTE_WIDTH-1-i) +: 4]);
|
||||||
|
end
|
||||||
|
endgenerate
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
uart_tx #(
|
||||||
|
.CLK_FREQ ( CLK_FREQ ),
|
||||||
|
.BAUD_RATE ( BAUD_RATE ),
|
||||||
|
.PARITY ( PARITY ),
|
||||||
|
.STOP_BITS ( 4 ),
|
||||||
|
.BYTE_WIDTH ( 2 * BYTE_WIDTH ),
|
||||||
|
.FIFO_EA ( 9 ),
|
||||||
|
.EXTRA_BYTE_AFTER_TRANSFER ( " " ),
|
||||||
|
.EXTRA_BYTE_AFTER_PACKET ( "\n" )
|
||||||
|
) u_uart_tx (
|
||||||
|
.rstn ( rstn ),
|
||||||
|
.clk ( clk ),
|
||||||
|
.i_tready ( ),
|
||||||
|
.i_tvalid ( tx_valid ),
|
||||||
|
.i_tdata ( tx_data ),
|
||||||
|
.i_tkeep ( {(2*BYTE_WIDTH){1'b1}} ),
|
||||||
|
.i_tlast ( tx_last ),
|
||||||
|
.o_uart_tx ( o_uart_tx )
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
endmodule
|
335
example-uart-read-write/uart/uart_rx.v
Normal file
335
example-uart-read-write/uart/uart_rx.v
Normal file
@ -0,0 +1,335 @@
|
|||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------------
|
||||||
|
// Module : uart_rx
|
||||||
|
// Type : synthesizable, IP's top
|
||||||
|
// Standard: Verilog 2001 (IEEE1364-2001)
|
||||||
|
// Function: input UART signal,
|
||||||
|
// output AXI-stream (configurable byte data width)
|
||||||
|
//--------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
module uart_rx #(
|
||||||
|
// clock frequency
|
||||||
|
parameter CLK_FREQ = 50000000, // clk frequency, Unit : Hz
|
||||||
|
// UART format
|
||||||
|
parameter BAUD_RATE = 115200, // Unit : Hz
|
||||||
|
parameter PARITY = "NONE", // "NONE", "ODD", or "EVEN"
|
||||||
|
// RX fifo depth
|
||||||
|
parameter FIFO_EA = 0 // 0:no fifo 1,2:depth=4 3:depth=8 4:depth=16 ... 10:depth=1024 11:depth=2048 ...
|
||||||
|
) (
|
||||||
|
input wire rstn,
|
||||||
|
input wire clk,
|
||||||
|
// UART RX input signal
|
||||||
|
input wire i_uart_rx,
|
||||||
|
// output AXI-stream master. Associated clock = clk.
|
||||||
|
input wire o_tready,
|
||||||
|
output reg o_tvalid,
|
||||||
|
output reg [ 7:0] o_tdata,
|
||||||
|
// report whether there's a overflow
|
||||||
|
output reg o_overflow
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
// Generate fractional precise upper limit for counter
|
||||||
|
//---------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
localparam BAUD_CYCLES = ( (CLK_FREQ*10*2 + BAUD_RATE) / (BAUD_RATE*2) ) / 10 ;
|
||||||
|
localparam BAUD_CYCLES_FRAC = ( (CLK_FREQ*10*2 + BAUD_RATE) / (BAUD_RATE*2) ) % 10 ;
|
||||||
|
|
||||||
|
localparam HALF_BAUD_CYCLES = BAUD_CYCLES / 2;
|
||||||
|
localparam THREE_QUARTER_BAUD_CYCLES = (BAUD_CYCLES*3) / 4;
|
||||||
|
|
||||||
|
localparam [9:0] ADDITION_CYCLES = (BAUD_CYCLES_FRAC == 0) ? 10'b0000000000 :
|
||||||
|
(BAUD_CYCLES_FRAC == 1) ? 10'b0000010000 :
|
||||||
|
(BAUD_CYCLES_FRAC == 2) ? 10'b0010000100 :
|
||||||
|
(BAUD_CYCLES_FRAC == 3) ? 10'b0010010010 :
|
||||||
|
(BAUD_CYCLES_FRAC == 4) ? 10'b0101001010 :
|
||||||
|
(BAUD_CYCLES_FRAC == 5) ? 10'b0101010101 :
|
||||||
|
(BAUD_CYCLES_FRAC == 6) ? 10'b1010110101 :
|
||||||
|
(BAUD_CYCLES_FRAC == 7) ? 10'b1101101101 :
|
||||||
|
(BAUD_CYCLES_FRAC == 8) ? 10'b1101111011 :
|
||||||
|
/*BAUD_CYCLES_FRAC == 9)*/ 10'b1111101111 ;
|
||||||
|
|
||||||
|
wire [31:0] cycles [9:0];
|
||||||
|
|
||||||
|
assign cycles[0] = BAUD_CYCLES + (ADDITION_CYCLES[0] ? 1 : 0);
|
||||||
|
assign cycles[1] = BAUD_CYCLES + (ADDITION_CYCLES[1] ? 1 : 0);
|
||||||
|
assign cycles[2] = BAUD_CYCLES + (ADDITION_CYCLES[2] ? 1 : 0);
|
||||||
|
assign cycles[3] = BAUD_CYCLES + (ADDITION_CYCLES[3] ? 1 : 0);
|
||||||
|
assign cycles[4] = BAUD_CYCLES + (ADDITION_CYCLES[4] ? 1 : 0);
|
||||||
|
assign cycles[5] = BAUD_CYCLES + (ADDITION_CYCLES[5] ? 1 : 0);
|
||||||
|
assign cycles[6] = BAUD_CYCLES + (ADDITION_CYCLES[6] ? 1 : 0);
|
||||||
|
assign cycles[7] = BAUD_CYCLES + (ADDITION_CYCLES[7] ? 1 : 0);
|
||||||
|
assign cycles[8] = BAUD_CYCLES + (ADDITION_CYCLES[8] ? 1 : 0);
|
||||||
|
assign cycles[9] = BAUD_CYCLES + (ADDITION_CYCLES[9] ? 1 : 0);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
// Input beat
|
||||||
|
//---------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
reg rx_d1 = 1'b0;
|
||||||
|
|
||||||
|
always @ (posedge clk or negedge rstn)
|
||||||
|
if (~rstn)
|
||||||
|
rx_d1 <= 1'b0;
|
||||||
|
else
|
||||||
|
rx_d1 <= i_uart_rx;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
// count continuous '1'
|
||||||
|
//---------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
reg [31:0] count1 = 0;
|
||||||
|
|
||||||
|
always @ (posedge clk or negedge rstn)
|
||||||
|
if (~rstn) begin
|
||||||
|
count1 <= 0;
|
||||||
|
end else begin
|
||||||
|
if (rx_d1)
|
||||||
|
count1 <= (count1 < 'hFFFFFFFF) ? (count1 + 1) : count1;
|
||||||
|
else
|
||||||
|
count1 <= 0;
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
// main FSM
|
||||||
|
//---------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
localparam [ 3:0] TOTAL_BITS_MINUS1 = (PARITY == "ODD" || PARITY == "EVEN") ? 4'd9 : 4'd8;
|
||||||
|
|
||||||
|
localparam [ 1:0] S_IDLE = 2'd0 ,
|
||||||
|
S_RX = 2'd1 ,
|
||||||
|
S_STOP_BIT = 2'd2 ;
|
||||||
|
|
||||||
|
reg [ 1:0] state = S_IDLE;
|
||||||
|
reg [ 8:0] rxbits = 9'b0;
|
||||||
|
reg [ 3:0] rxcnt = 4'd0;
|
||||||
|
reg [31:0] cycle = 1;
|
||||||
|
reg [32:0] countp = 33'h1_0000_0000; // countp>=0x100000000 means '1' is majority , countp<0x100000000 means '0' is majority
|
||||||
|
wire rxbit = countp[32]; // countp>=0x100000000 corresponds to countp[32]==1, countp<0x100000000 corresponds to countp[32]==0
|
||||||
|
|
||||||
|
wire [ 7:0] rbyte = (PARITY == "ODD" ) ? rxbits[7:0] :
|
||||||
|
(PARITY == "EVEN") ? rxbits[7:0] :
|
||||||
|
/*(PARITY == "NONE")*/ rxbits[8:1] ;
|
||||||
|
|
||||||
|
wire parity_correct = (PARITY == "ODD" ) ? ((~(^(rbyte))) == rxbits[8]) :
|
||||||
|
(PARITY == "EVEN") ? ( (^(rbyte)) == rxbits[8]) :
|
||||||
|
/*(PARITY == "NONE")*/ 1'b1 ;
|
||||||
|
|
||||||
|
|
||||||
|
always @ (posedge clk or negedge rstn)
|
||||||
|
if (~rstn) begin
|
||||||
|
state <= S_IDLE;
|
||||||
|
rxbits <= 9'b0;
|
||||||
|
rxcnt <= 4'd0;
|
||||||
|
cycle <= 1;
|
||||||
|
countp <= 33'h1_0000_0000;
|
||||||
|
end else begin
|
||||||
|
case (state)
|
||||||
|
S_IDLE : begin
|
||||||
|
if ((count1 >= THREE_QUARTER_BAUD_CYCLES) && (rx_d1 == 1'b0)) // receive a '0' which is followed by continuous '1' for half baud cycles
|
||||||
|
state <= S_RX;
|
||||||
|
rxcnt <= 4'd0;
|
||||||
|
cycle <= 2; // we've already receive a '0', so here cycle = 2
|
||||||
|
countp <= (33'h1_0000_0000 - 33'd1); // we've already receive a '0', so here countp = initial_value - 1
|
||||||
|
end
|
||||||
|
|
||||||
|
S_RX :
|
||||||
|
if ( cycle < cycles[rxcnt] ) begin // cycle loop from 1 to cycles[rxcnt]
|
||||||
|
cycle <= cycle + 1;
|
||||||
|
countp <= rx_d1 ? (countp + 33'd1) : (countp - 33'd1);
|
||||||
|
end else begin
|
||||||
|
cycle <= 1; // reset counter
|
||||||
|
countp <= 33'h1_0000_0000; // reset counter
|
||||||
|
|
||||||
|
if ( rxcnt < TOTAL_BITS_MINUS1 ) begin // rxcnt loop from 0 to TOTAL_BITS_MINUS1
|
||||||
|
rxcnt <= rxcnt + 4'd1;
|
||||||
|
if ((rxcnt == 4'd0) && (rxbit == 1'b1)) // except start bit, but get '1'
|
||||||
|
state <= S_IDLE; // RX failed, back to IDLE
|
||||||
|
end else begin
|
||||||
|
rxcnt <= 4'd0;
|
||||||
|
state <= S_STOP_BIT;
|
||||||
|
end
|
||||||
|
|
||||||
|
rxbits <= {rxbit, rxbits[8:1]}; // put current rxbit to MSB of rxbits, and right shift other bits
|
||||||
|
end
|
||||||
|
|
||||||
|
default : // S_STOP_BIT
|
||||||
|
if ( cycle < THREE_QUARTER_BAUD_CYCLES) begin // cycle loop from 1 to THREE_QUARTER_BAUD_CYCLES
|
||||||
|
cycle <= cycle + 1;
|
||||||
|
end else begin
|
||||||
|
cycle <= 1; // reset counter
|
||||||
|
state <= S_IDLE; // back to IDLE
|
||||||
|
end
|
||||||
|
endcase
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
// RX result byte
|
||||||
|
//---------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
reg f_tvalid = 1'b0;
|
||||||
|
reg [7:0] f_tdata = 8'h0;
|
||||||
|
|
||||||
|
always @ (posedge clk or negedge rstn)
|
||||||
|
if (~rstn) begin
|
||||||
|
f_tvalid <= 1'b0;
|
||||||
|
f_tdata <= 8'h0;
|
||||||
|
end else begin
|
||||||
|
f_tvalid <= 1'b0;
|
||||||
|
f_tdata <= 8'h0;
|
||||||
|
if (state == S_STOP_BIT) begin
|
||||||
|
if ( cycle < THREE_QUARTER_BAUD_CYCLES) begin
|
||||||
|
end else begin
|
||||||
|
if ((count1 >= HALF_BAUD_CYCLES) && parity_correct) begin // stop bit have enough '1', and parity correct
|
||||||
|
f_tvalid <= 1'b1;
|
||||||
|
f_tdata <= rbyte; // received a correct byte, output it
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
// RX fifo
|
||||||
|
//---------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
wire f_tready;
|
||||||
|
|
||||||
|
generate if (FIFO_EA <= 0) begin // no RX fifo
|
||||||
|
|
||||||
|
assign f_tready = o_tready;
|
||||||
|
always @ (*) o_tvalid = f_tvalid;
|
||||||
|
always @ (*) o_tdata = f_tdata;
|
||||||
|
|
||||||
|
end else begin // TX fifo
|
||||||
|
|
||||||
|
localparam EA = (FIFO_EA <= 2) ? 2 : FIFO_EA;
|
||||||
|
|
||||||
|
reg [7:0] buffer [ ((1<<EA)-1) : 0 ];
|
||||||
|
|
||||||
|
localparam [EA:0] A_ZERO = {{EA{1'b0}}, 1'b0};
|
||||||
|
localparam [EA:0] A_ONE = {{EA{1'b0}}, 1'b1};
|
||||||
|
|
||||||
|
reg [EA:0] wptr = A_ZERO;
|
||||||
|
reg [EA:0] wptr_d1 = A_ZERO;
|
||||||
|
reg [EA:0] wptr_d2 = A_ZERO;
|
||||||
|
reg [EA:0] rptr = A_ZERO;
|
||||||
|
wire [EA:0] rptr_next = (o_tvalid & o_tready) ? (rptr+A_ONE) : rptr;
|
||||||
|
|
||||||
|
assign f_tready = ( wptr != {~rptr[EA], rptr[EA-1:0]} );
|
||||||
|
|
||||||
|
always @ (posedge clk or negedge rstn)
|
||||||
|
if (~rstn) begin
|
||||||
|
wptr <= A_ZERO;
|
||||||
|
wptr_d1 <= A_ZERO;
|
||||||
|
wptr_d2 <= A_ZERO;
|
||||||
|
end else begin
|
||||||
|
if (f_tvalid & f_tready)
|
||||||
|
wptr <= wptr + A_ONE;
|
||||||
|
wptr_d1 <= wptr;
|
||||||
|
wptr_d2 <= wptr_d1;
|
||||||
|
end
|
||||||
|
|
||||||
|
always @ (posedge clk)
|
||||||
|
if (f_tvalid & f_tready)
|
||||||
|
buffer[wptr[EA-1:0]] <= f_tdata;
|
||||||
|
|
||||||
|
always @ (posedge clk or negedge rstn)
|
||||||
|
if (~rstn) begin
|
||||||
|
rptr <= A_ZERO;
|
||||||
|
o_tvalid <= 1'b0;
|
||||||
|
end else begin
|
||||||
|
rptr <= rptr_next;
|
||||||
|
o_tvalid <= (rptr_next != wptr_d2);
|
||||||
|
end
|
||||||
|
|
||||||
|
always @ (posedge clk)
|
||||||
|
o_tdata <= buffer[rptr_next[EA-1:0]];
|
||||||
|
|
||||||
|
initial o_tvalid = 1'b0;
|
||||||
|
initial o_tdata = 8'h0;
|
||||||
|
end endgenerate
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
// detect RX fifo overflow
|
||||||
|
//---------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
initial o_overflow = 1'b0;
|
||||||
|
|
||||||
|
always @ (posedge clk or negedge rstn)
|
||||||
|
if (~rstn)
|
||||||
|
o_overflow <= 1'b0;
|
||||||
|
else
|
||||||
|
o_overflow <= (f_tvalid & (~f_tready));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
// parameter checking
|
||||||
|
//---------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
initial begin
|
||||||
|
if (BAUD_CYCLES < 10) begin $error("invalid parameter : BAUD_CYCLES < 10, please use a faster driving clock"); $stop; end
|
||||||
|
|
||||||
|
$display("uart_rx : parity = %s" , PARITY );
|
||||||
|
$display("uart_rx : clock period = %.0f ns (%-10d Hz)" , 1000000000.0/CLK_FREQ , CLK_FREQ );
|
||||||
|
$display("uart_rx : baud rate period = %.0f ns (%-10d Hz)" , 1000000000.0/BAUD_RATE , BAUD_RATE);
|
||||||
|
$display("uart_rx : baud cycles = %-10d" , BAUD_CYCLES );
|
||||||
|
$display("uart_rx : baud cycles frac = %-10d" , BAUD_CYCLES_FRAC );
|
||||||
|
|
||||||
|
if (PARITY == "ODD" || PARITY == "EVEN") begin
|
||||||
|
$display("uart_rx : __ ____ ____ ____ ____ ____ ____ ____ ____________ ");
|
||||||
|
$display("uart_rx : wave \\____/____X____X____X____X____X____X____X____X____/ ");
|
||||||
|
$display("uart_rx : bits | S | B0 | B1 | B2 | B3 | B4 | B5 | B6 | B7 | P | ");
|
||||||
|
$display("uart_rx : time_points t0 t1 t2 t3 t4 t5 t6 t7 t8 t9 t10 ");
|
||||||
|
$display("uart_rx :");
|
||||||
|
end else begin
|
||||||
|
$display("uart_rx : __ ____ ____ ____ ____ ____ ____ ____ _______ ");
|
||||||
|
$display("uart_rx : wave \\____/____X____X____X____X____X____X____X____/ ");
|
||||||
|
$display("uart_rx : bits | S | B0 | B1 | B2 | B3 | B4 | B5 | B6 | B7 | ");
|
||||||
|
$display("uart_rx : time_points t0 t1 t2 t3 t4 t5 t6 t7 t8 t9 ");
|
||||||
|
$display("uart_rx :");
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
generate genvar index;
|
||||||
|
for (index=0; index<=9; index=index+1) begin : print_and_check_time
|
||||||
|
localparam cycles_acc = ( (index >= 0) ? (BAUD_CYCLES + (ADDITION_CYCLES[0] ? 1 : 0)) : 0 )
|
||||||
|
+ ( (index >= 1) ? (BAUD_CYCLES + (ADDITION_CYCLES[1] ? 1 : 0)) : 0 )
|
||||||
|
+ ( (index >= 2) ? (BAUD_CYCLES + (ADDITION_CYCLES[2] ? 1 : 0)) : 0 )
|
||||||
|
+ ( (index >= 3) ? (BAUD_CYCLES + (ADDITION_CYCLES[3] ? 1 : 0)) : 0 )
|
||||||
|
+ ( (index >= 4) ? (BAUD_CYCLES + (ADDITION_CYCLES[4] ? 1 : 0)) : 0 )
|
||||||
|
+ ( (index >= 5) ? (BAUD_CYCLES + (ADDITION_CYCLES[5] ? 1 : 0)) : 0 )
|
||||||
|
+ ( (index >= 6) ? (BAUD_CYCLES + (ADDITION_CYCLES[6] ? 1 : 0)) : 0 )
|
||||||
|
+ ( (index >= 7) ? (BAUD_CYCLES + (ADDITION_CYCLES[7] ? 1 : 0)) : 0 )
|
||||||
|
+ ( (index >= 8) ? (BAUD_CYCLES + (ADDITION_CYCLES[8] ? 1 : 0)) : 0 )
|
||||||
|
+ ( (index >= 9) ? (BAUD_CYCLES + (ADDITION_CYCLES[9] ? 1 : 0)) : 0 ) ;
|
||||||
|
|
||||||
|
localparam real ideal_time_ns = ((index+1)*1000000000.0/BAUD_RATE);
|
||||||
|
localparam real actual_time_ns = (cycles_acc*1000000000.0/CLK_FREQ);
|
||||||
|
localparam real uncertainty = (1000000000.0/CLK_FREQ);
|
||||||
|
localparam real error = ( (ideal_time_ns>actual_time_ns) ? (ideal_time_ns-actual_time_ns) : (-ideal_time_ns+actual_time_ns) ) + uncertainty;
|
||||||
|
localparam real relative_error_percent = (error / (1000000000.0/BAUD_RATE)) * 100.0;
|
||||||
|
|
||||||
|
initial if (PARITY == "ODD" || PARITY == "EVEN" || index < 9) begin
|
||||||
|
$display("uart_rx : t%-2d- t0 = %.0f ns (ideal) %.0f +- %.0f ns (actual). error=%.0f ns relative_error=%.3f%%" ,
|
||||||
|
(index+1) ,
|
||||||
|
ideal_time_ns ,
|
||||||
|
actual_time_ns,
|
||||||
|
uncertainty,
|
||||||
|
error,
|
||||||
|
relative_error_percent
|
||||||
|
);
|
||||||
|
|
||||||
|
if ( relative_error_percent > 8.0 ) begin $error("relative_error is too large"); $stop; end // if relative error larger than 8%
|
||||||
|
end
|
||||||
|
end
|
||||||
|
endgenerate
|
||||||
|
|
||||||
|
|
||||||
|
endmodule
|
340
example-uart-read-write/uart/uart_tx.v
Normal file
340
example-uart-read-write/uart/uart_tx.v
Normal file
@ -0,0 +1,340 @@
|
|||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------------
|
||||||
|
// Module : uart_tx
|
||||||
|
// Type : synthesizable, IP's top
|
||||||
|
// Standard: Verilog 2001 (IEEE1364-2001)
|
||||||
|
// Function: input AXI-stream (configurable data width),
|
||||||
|
// output UART signal
|
||||||
|
//--------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
module uart_tx #(
|
||||||
|
// clock frequency
|
||||||
|
parameter CLK_FREQ = 50000000, // clk frequency, Unit : Hz
|
||||||
|
// UART format
|
||||||
|
parameter BAUD_RATE = 115200, // Unit : Hz
|
||||||
|
parameter PARITY = "NONE", // "NONE", "ODD", or "EVEN"
|
||||||
|
parameter STOP_BITS = 2, // can be 1, 2, 3, 4, ...
|
||||||
|
// AXI stream data width
|
||||||
|
parameter BYTE_WIDTH = 1, // can be 1, 2, 3, 4, ...
|
||||||
|
// TX fifo depth
|
||||||
|
parameter FIFO_EA = 0, // 0:no fifo 1,2:depth=4 3:depth=8 4:depth=16 ... 10:depth=1024 11:depth=2048 ...
|
||||||
|
// do you want to send extra byte after each AXI-stream transfer or packet?
|
||||||
|
parameter EXTRA_BYTE_AFTER_TRANSFER = "", // specify a extra byte to send after each AXI-stream transfer. when ="", do not send this extra byte
|
||||||
|
parameter EXTRA_BYTE_AFTER_PACKET = "" // specify a extra byte to send after each AXI-stream packet . when ="", do not send this extra byte
|
||||||
|
) (
|
||||||
|
input wire rstn,
|
||||||
|
input wire clk,
|
||||||
|
// input stream : AXI-stream slave. Associated clock = clk
|
||||||
|
output wire i_tready,
|
||||||
|
input wire i_tvalid,
|
||||||
|
input wire [8*BYTE_WIDTH-1:0] i_tdata,
|
||||||
|
input wire [ BYTE_WIDTH-1:0] i_tkeep,
|
||||||
|
input wire i_tlast,
|
||||||
|
// UART TX output signal
|
||||||
|
output reg o_uart_tx
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
// TX fifo
|
||||||
|
//---------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
wire f_tready;
|
||||||
|
reg f_tvalid;
|
||||||
|
reg [8*BYTE_WIDTH-1:0] f_tdata;
|
||||||
|
reg [ BYTE_WIDTH-1:0] f_tkeep;
|
||||||
|
reg f_tlast;
|
||||||
|
|
||||||
|
generate if (FIFO_EA <= 0) begin // no TX fifo
|
||||||
|
|
||||||
|
assign i_tready = f_tready;
|
||||||
|
always @ (*) f_tvalid = i_tvalid;
|
||||||
|
always @ (*) f_tdata = i_tdata;
|
||||||
|
always @ (*) f_tkeep = i_tkeep;
|
||||||
|
always @ (*) f_tlast = i_tlast;
|
||||||
|
|
||||||
|
end else begin // TX fifo
|
||||||
|
|
||||||
|
localparam EA = (FIFO_EA<=2) ? 2 : FIFO_EA;
|
||||||
|
localparam DW = ( 1 + BYTE_WIDTH + 8*BYTE_WIDTH ); // 1-bit tlast, (BYTE_WIDTH)-bit tkeep, (8*BYTE_WIDTH)-bit tdata
|
||||||
|
|
||||||
|
reg [DW-1:0] buffer [ ((1<<EA)-1) : 0 ];
|
||||||
|
|
||||||
|
localparam [EA:0] A_ZERO = {{EA{1'b0}}, 1'b0};
|
||||||
|
localparam [EA:0] A_ONE = {{EA{1'b0}}, 1'b1};
|
||||||
|
|
||||||
|
reg [EA:0] wptr = A_ZERO;
|
||||||
|
reg [EA:0] wptr_d1 = A_ZERO;
|
||||||
|
reg [EA:0] wptr_d2 = A_ZERO;
|
||||||
|
reg [EA:0] rptr = A_ZERO;
|
||||||
|
wire [EA:0] rptr_next = (f_tvalid & f_tready) ? (rptr+A_ONE) : rptr;
|
||||||
|
|
||||||
|
assign i_tready = ( wptr != {~rptr[EA], rptr[EA-1:0]} );
|
||||||
|
|
||||||
|
always @ (posedge clk or negedge rstn)
|
||||||
|
if (~rstn) begin
|
||||||
|
wptr <= A_ZERO;
|
||||||
|
wptr_d1 <= A_ZERO;
|
||||||
|
wptr_d2 <= A_ZERO;
|
||||||
|
end else begin
|
||||||
|
if (i_tvalid & i_tready)
|
||||||
|
wptr <= wptr + A_ONE;
|
||||||
|
wptr_d1 <= wptr;
|
||||||
|
wptr_d2 <= wptr_d1;
|
||||||
|
end
|
||||||
|
|
||||||
|
always @ (posedge clk)
|
||||||
|
if (i_tvalid & i_tready)
|
||||||
|
buffer[wptr[EA-1:0]] <= {i_tlast, i_tkeep, i_tdata};
|
||||||
|
|
||||||
|
always @ (posedge clk or negedge rstn)
|
||||||
|
if (~rstn) begin
|
||||||
|
rptr <= A_ZERO;
|
||||||
|
f_tvalid <= 1'b0;
|
||||||
|
end else begin
|
||||||
|
rptr <= rptr_next;
|
||||||
|
f_tvalid <= (rptr_next != wptr_d2);
|
||||||
|
end
|
||||||
|
|
||||||
|
always @ (posedge clk)
|
||||||
|
{f_tlast, f_tkeep, f_tdata} <= buffer[rptr_next[EA-1:0]];
|
||||||
|
|
||||||
|
initial {f_tvalid, f_tlast, f_tkeep, f_tdata} = 0;
|
||||||
|
|
||||||
|
end endgenerate
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
// Generate fractional precise upper limit for counter
|
||||||
|
//---------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
localparam BAUD_CYCLES = ( (CLK_FREQ*10*2 + BAUD_RATE) / (BAUD_RATE*2) ) / 10 ;
|
||||||
|
localparam BAUD_CYCLES_FRAC = ( (CLK_FREQ*10*2 + BAUD_RATE) / (BAUD_RATE*2) ) % 10 ;
|
||||||
|
localparam STOP_BIT_CYCLES = (BAUD_CYCLES_FRAC == 0) ? BAUD_CYCLES : (BAUD_CYCLES + 1);
|
||||||
|
|
||||||
|
localparam [9:0] ADDITION_CYCLES = (BAUD_CYCLES_FRAC == 0) ? 10'b0000000000 :
|
||||||
|
(BAUD_CYCLES_FRAC == 1) ? 10'b0000010000 :
|
||||||
|
(BAUD_CYCLES_FRAC == 2) ? 10'b0010000100 :
|
||||||
|
(BAUD_CYCLES_FRAC == 3) ? 10'b0010010010 :
|
||||||
|
(BAUD_CYCLES_FRAC == 4) ? 10'b0101001010 :
|
||||||
|
(BAUD_CYCLES_FRAC == 5) ? 10'b0101010101 :
|
||||||
|
(BAUD_CYCLES_FRAC == 6) ? 10'b1010110101 :
|
||||||
|
(BAUD_CYCLES_FRAC == 7) ? 10'b1101101101 :
|
||||||
|
(BAUD_CYCLES_FRAC == 8) ? 10'b1101111011 :
|
||||||
|
/*BAUD_CYCLES_FRAC == 9)*/ 10'b1111101111 ;
|
||||||
|
|
||||||
|
wire [31:0] cycles [9:0];
|
||||||
|
|
||||||
|
assign cycles[0] = BAUD_CYCLES + (ADDITION_CYCLES[0] ? 1 : 0);
|
||||||
|
assign cycles[1] = BAUD_CYCLES + (ADDITION_CYCLES[1] ? 1 : 0);
|
||||||
|
assign cycles[2] = BAUD_CYCLES + (ADDITION_CYCLES[2] ? 1 : 0);
|
||||||
|
assign cycles[3] = BAUD_CYCLES + (ADDITION_CYCLES[3] ? 1 : 0);
|
||||||
|
assign cycles[4] = BAUD_CYCLES + (ADDITION_CYCLES[4] ? 1 : 0);
|
||||||
|
assign cycles[5] = BAUD_CYCLES + (ADDITION_CYCLES[5] ? 1 : 0);
|
||||||
|
assign cycles[6] = BAUD_CYCLES + (ADDITION_CYCLES[6] ? 1 : 0);
|
||||||
|
assign cycles[7] = BAUD_CYCLES + (ADDITION_CYCLES[7] ? 1 : 0);
|
||||||
|
assign cycles[8] = BAUD_CYCLES + (ADDITION_CYCLES[8] ? 1 : 0);
|
||||||
|
assign cycles[9] = BAUD_CYCLES + (ADDITION_CYCLES[9] ? 1 : 0);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
//---------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
localparam [BYTE_WIDTH-1:0] ZERO_KEEP = 0;
|
||||||
|
|
||||||
|
localparam [31:0] PARITY_BITS = (PARITY == "ODD" || PARITY == "EVEN") ? 1 : 0;
|
||||||
|
localparam [31:0] TOTAL_BITS = (STOP_BITS >= ('hFFFFFFFF-9-PARITY_BITS)) ? 'hFFFFFFFF : (PARITY_BITS+STOP_BITS+9);
|
||||||
|
|
||||||
|
localparam [ 0:0] BYTE_T_EN = (EXTRA_BYTE_AFTER_TRANSFER == "") ? 1'b0 : 1'b1;
|
||||||
|
localparam [ 0:0] BYTE_B_EN = (EXTRA_BYTE_AFTER_PACKET == "") ? 1'b0 : 1'b1;
|
||||||
|
localparam [ 7:0] BYTE_T = EXTRA_BYTE_AFTER_TRANSFER;
|
||||||
|
localparam [ 7:0] BYTE_P = EXTRA_BYTE_AFTER_PACKET;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
// function for calculate parity bit
|
||||||
|
//---------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
function [0:0] get_parity;
|
||||||
|
input [7:0] data;
|
||||||
|
begin
|
||||||
|
get_parity = (PARITY == "ODD" ) ? (~(^(data[7:0]))) :
|
||||||
|
(PARITY == "EVEN") ? (^(data[7:0])) :
|
||||||
|
/*(PARITY == "NONE")*/ 1'b1 ;
|
||||||
|
end
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
// main FSM
|
||||||
|
//---------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
localparam [ 1:0] S_IDLE = 2'b01 , // only in state S_IDLE, state[0]==1, the goal is to make f_tready pure register-out
|
||||||
|
S_PREPARE = 2'b00 ,
|
||||||
|
S_TX = 2'b10 ;
|
||||||
|
|
||||||
|
reg [ 1:0] state = S_IDLE; // FSM state register
|
||||||
|
|
||||||
|
reg [8*BYTE_WIDTH-1:0] data = 0;
|
||||||
|
reg [ BYTE_WIDTH-1:0] keep = 0;
|
||||||
|
reg byte_t_en = 1'b0;
|
||||||
|
reg byte_p_en = 1'b0;
|
||||||
|
reg [ 9:0] txbits = 10'b0;
|
||||||
|
reg [ 31:0] txcnt = 0;
|
||||||
|
reg [ 31:0] cycle = 1;
|
||||||
|
|
||||||
|
|
||||||
|
always @ (posedge clk or negedge rstn)
|
||||||
|
if (~rstn) begin
|
||||||
|
state <= S_IDLE;
|
||||||
|
data <= 0;
|
||||||
|
keep <= 0;
|
||||||
|
byte_t_en <= 1'b0;
|
||||||
|
byte_p_en <= 1'b0;
|
||||||
|
txbits <= 10'b0;
|
||||||
|
txcnt <= 0;
|
||||||
|
cycle <= 1;
|
||||||
|
end else begin
|
||||||
|
case (state)
|
||||||
|
S_IDLE : begin
|
||||||
|
state <= f_tvalid ? S_PREPARE : S_IDLE;
|
||||||
|
data <= f_tdata;
|
||||||
|
keep <= f_tkeep;
|
||||||
|
byte_t_en <= BYTE_T_EN;
|
||||||
|
byte_p_en <= BYTE_B_EN & f_tlast;
|
||||||
|
txbits <= 10'b0;
|
||||||
|
txcnt <= 0;
|
||||||
|
cycle <= 1;
|
||||||
|
end
|
||||||
|
|
||||||
|
S_PREPARE : begin
|
||||||
|
data <= (data >> 8);
|
||||||
|
keep <= (keep >> 1);
|
||||||
|
if ( keep[0] == 1'b1 ) begin
|
||||||
|
txbits <= {get_parity(data[7:0]), data[7:0], 1'b0};
|
||||||
|
state <= S_TX;
|
||||||
|
end else if ( keep != ZERO_KEEP ) begin
|
||||||
|
state <= S_PREPARE;
|
||||||
|
end else if ( byte_t_en ) begin
|
||||||
|
byte_t_en <= 1'b0;
|
||||||
|
txbits <= {get_parity(BYTE_T), BYTE_T, 1'b0};
|
||||||
|
state <= S_TX;
|
||||||
|
end else if ( byte_p_en ) begin
|
||||||
|
byte_p_en <= 1'b0;
|
||||||
|
txbits <= {get_parity(BYTE_P), BYTE_P, 1'b0};
|
||||||
|
state <= S_TX;
|
||||||
|
end else begin
|
||||||
|
state <= S_IDLE;
|
||||||
|
end
|
||||||
|
txcnt <= 0;
|
||||||
|
cycle <= 1;
|
||||||
|
end
|
||||||
|
|
||||||
|
default : begin // S_TX
|
||||||
|
if (keep[0] == 1'b0) begin
|
||||||
|
data <= (data >> 8);
|
||||||
|
keep <= (keep >> 1);
|
||||||
|
end
|
||||||
|
if ( cycle < ((txcnt<=9) ? cycles[txcnt] : STOP_BIT_CYCLES) ) begin // cycle loop from 1 to ((txcnt<=9) ? cycles[txcnt] : STOP_BIT_CYCLES)
|
||||||
|
cycle <= cycle + 1;
|
||||||
|
end else begin
|
||||||
|
cycle <= 1;
|
||||||
|
txbits <= {1'b1, txbits[9:1]}; // right shift txbits, and fill '1' to MSB
|
||||||
|
if ( txcnt < (TOTAL_BITS-1) ) begin // txcnt loop from 0 to (TOTAL_BITS-1)
|
||||||
|
txcnt <= txcnt + 1;
|
||||||
|
end else begin
|
||||||
|
txcnt <= 0;
|
||||||
|
state <= S_PREPARE;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
endcase
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
// generate UART output
|
||||||
|
//---------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
initial o_uart_tx = 1'b1;
|
||||||
|
|
||||||
|
always @ (posedge clk or negedge rstn)
|
||||||
|
if (~rstn)
|
||||||
|
o_uart_tx <= 1'b1;
|
||||||
|
else
|
||||||
|
o_uart_tx <= (state == S_TX) ? txbits[0] : 1'b1;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
// generate AXI-stream TREADY
|
||||||
|
//---------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
assign f_tready = state[0]; // (state == S_IDLE)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
// parameter checking
|
||||||
|
//---------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
initial begin
|
||||||
|
if (BYTE_WIDTH <= 0) begin $error("invalid parameter : BYTE_WIDTH<=0"); $stop; end
|
||||||
|
if (STOP_BITS <= 0) begin $error("invalid parameter : STOP_BITS <=0"); $stop; end
|
||||||
|
if (BAUD_CYCLES < 1) begin $error("invalid parameter : BAUD_CYCLES < 1, please use a faster driving clock"); $stop; end
|
||||||
|
|
||||||
|
$display("uart_tx : parity = %s" , PARITY );
|
||||||
|
$display("uart_tx : clock period = %.0f ns (%-10d Hz)" , 1000000000.0/CLK_FREQ , CLK_FREQ );
|
||||||
|
$display("uart_tx : baud rate period = %.0f ns (%-10d Hz)" , 1000000000.0/BAUD_RATE , BAUD_RATE);
|
||||||
|
$display("uart_tx : baud cycles = %-10d" , BAUD_CYCLES );
|
||||||
|
$display("uart_tx : baud cycles frac = %-10d" , BAUD_CYCLES_FRAC );
|
||||||
|
|
||||||
|
if (PARITY == "ODD" || PARITY == "EVEN") begin
|
||||||
|
$display("uart_tx : __ ____ ____ ____ ____ ____ ____ ____ ____________ ");
|
||||||
|
$display("uart_tx : wave \\____/____X____X____X____X____X____X____X____X____/ ");
|
||||||
|
$display("uart_tx : bits | S | B0 | B1 | B2 | B3 | B4 | B5 | B6 | B7 | P | ");
|
||||||
|
$display("uart_tx : time_points t0 t1 t2 t3 t4 t5 t6 t7 t8 t9 t10 ");
|
||||||
|
$display("uart_tx :");
|
||||||
|
end else begin
|
||||||
|
$display("uart_tx : __ ____ ____ ____ ____ ____ ____ ____ _______ ");
|
||||||
|
$display("uart_tx : wave \\____/____X____X____X____X____X____X____X____/ ");
|
||||||
|
$display("uart_tx : bits | S | B0 | B1 | B2 | B3 | B4 | B5 | B6 | B7 | ");
|
||||||
|
$display("uart_tx : time_points t0 t1 t2 t3 t4 t5 t6 t7 t8 t9 ");
|
||||||
|
$display("uart_tx :");
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
generate genvar index, i;
|
||||||
|
for (index=0; index<=9; index=index+1) begin : print_and_check_time
|
||||||
|
localparam cycles_acc = ( (index >= 0) ? (BAUD_CYCLES + (ADDITION_CYCLES[0] ? 1 : 0)) : 0 )
|
||||||
|
+ ( (index >= 1) ? (BAUD_CYCLES + (ADDITION_CYCLES[1] ? 1 : 0)) : 0 )
|
||||||
|
+ ( (index >= 2) ? (BAUD_CYCLES + (ADDITION_CYCLES[2] ? 1 : 0)) : 0 )
|
||||||
|
+ ( (index >= 3) ? (BAUD_CYCLES + (ADDITION_CYCLES[3] ? 1 : 0)) : 0 )
|
||||||
|
+ ( (index >= 4) ? (BAUD_CYCLES + (ADDITION_CYCLES[4] ? 1 : 0)) : 0 )
|
||||||
|
+ ( (index >= 5) ? (BAUD_CYCLES + (ADDITION_CYCLES[5] ? 1 : 0)) : 0 )
|
||||||
|
+ ( (index >= 6) ? (BAUD_CYCLES + (ADDITION_CYCLES[6] ? 1 : 0)) : 0 )
|
||||||
|
+ ( (index >= 7) ? (BAUD_CYCLES + (ADDITION_CYCLES[7] ? 1 : 0)) : 0 )
|
||||||
|
+ ( (index >= 8) ? (BAUD_CYCLES + (ADDITION_CYCLES[8] ? 1 : 0)) : 0 )
|
||||||
|
+ ( (index >= 9) ? (BAUD_CYCLES + (ADDITION_CYCLES[9] ? 1 : 0)) : 0 ) ;
|
||||||
|
|
||||||
|
localparam real ideal_time_ns = ((index+1)*1000000000.0/BAUD_RATE);
|
||||||
|
localparam real actual_time_ns = (cycles_acc*1000000000.0/CLK_FREQ);
|
||||||
|
localparam real error = (ideal_time_ns>actual_time_ns) ? (ideal_time_ns-actual_time_ns) : (-ideal_time_ns+actual_time_ns);
|
||||||
|
localparam real relative_error_percent = (error / (1000000000.0/BAUD_RATE)) * 100.0;
|
||||||
|
|
||||||
|
initial if (PARITY == "ODD" || PARITY == "EVEN" || index < 9) begin
|
||||||
|
$display("uart_tx : t%-2d- t0 = %.0f ns (ideal) %.0f ns (actual). error=%.0f ns relative_error=%.3f%%" ,
|
||||||
|
(index+1) ,
|
||||||
|
ideal_time_ns ,
|
||||||
|
actual_time_ns,
|
||||||
|
error,
|
||||||
|
relative_error_percent
|
||||||
|
);
|
||||||
|
|
||||||
|
if ( relative_error_percent > 3.0 ) begin $error("relative_error is too large"); $stop; end // if relative error larger than 3%
|
||||||
|
end
|
||||||
|
end
|
||||||
|
endgenerate
|
||||||
|
|
||||||
|
|
||||||
|
endmodule
|
@ -1,401 +0,0 @@
|
|||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------------
|
|
||||||
// Module : uart2axi4
|
|
||||||
// Type : synthesizable
|
|
||||||
// Standard: SystemVerilog 2005 (IEEE1800-2005)
|
|
||||||
// Function: convert UART command to AXI4 read/write action
|
|
||||||
//--------------------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
module uart2axi4 #(
|
|
||||||
parameter A_WIDTH = 26,
|
|
||||||
parameter D_WIDTH = 16
|
|
||||||
) (
|
|
||||||
input wire rstn,
|
|
||||||
input wire clk,
|
|
||||||
|
|
||||||
output wire awvalid,
|
|
||||||
input wire awready,
|
|
||||||
output reg [A_WIDTH-1:0] awaddr,
|
|
||||||
output reg [ 7:0] awlen,
|
|
||||||
output wire wvalid,
|
|
||||||
input wire wready,
|
|
||||||
output wire wlast,
|
|
||||||
output wire [D_WIDTH-1:0] wdata,
|
|
||||||
input wire bvalid,
|
|
||||||
output wire bready,
|
|
||||||
output wire arvalid,
|
|
||||||
input wire arready,
|
|
||||||
output reg [A_WIDTH-1:0] araddr,
|
|
||||||
output reg [ 7:0] arlen,
|
|
||||||
input wire rvalid,
|
|
||||||
output wire rready,
|
|
||||||
input wire rlast,
|
|
||||||
input wire [D_WIDTH-1:0] rdata,
|
|
||||||
|
|
||||||
input wire uart_rx,
|
|
||||||
output wire uart_tx
|
|
||||||
);
|
|
||||||
|
|
||||||
function automatic logic isW(input [7:0] c);
|
|
||||||
return c==8'h57 || c==8'h77;
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function automatic logic isR(input [7:0] c);
|
|
||||||
return c==8'h52 || c==8'h72;
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function automatic logic isSpace(input [7:0] c);
|
|
||||||
return c==8'h20 || c==8'h09;
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function automatic logic isNewline(input [7:0] c);
|
|
||||||
return c==8'h0D || c==8'h0A;
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function automatic logic [3:0] isHex(input [7:0] c);
|
|
||||||
if(c>=8'h30 && c<= 8'h39)
|
|
||||||
return 1'b1;
|
|
||||||
else if(c>=8'h41 && c<=8'h46 || c>=8'h61 && c<=8'h66)
|
|
||||||
return 1'b1;
|
|
||||||
else
|
|
||||||
return 1'b0;
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function automatic logic [3:0] getHex(input [7:0] c);
|
|
||||||
if(c>=8'h30 && c<= 8'h39)
|
|
||||||
return c[3:0];
|
|
||||||
else if(c>=8'h41 && c<=8'h46 || c>=8'h61 && c<=8'h66)
|
|
||||||
return c[3:0] + 8'h9;
|
|
||||||
else
|
|
||||||
return 4'd0;
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
localparam V_WIDTH = A_WIDTH>D_WIDTH ? (A_WIDTH>8?A_WIDTH:8) : (D_WIDTH>8?D_WIDTH:8);
|
|
||||||
|
|
||||||
wire rx_valid;
|
|
||||||
wire [7:0] rx_data;
|
|
||||||
|
|
||||||
reg rw; // 0:write 1:read
|
|
||||||
reg [V_WIDTH-1:0] value;
|
|
||||||
reg [ 7:0] value_cnt;
|
|
||||||
reg wbuf_wen;
|
|
||||||
reg [ 7:0] wbuf_waddr;
|
|
||||||
reg [D_WIDTH-1:0] wbuf_wdata;
|
|
||||||
reg [ 7:0] wbuf_raddr;
|
|
||||||
reg [D_WIDTH-1:0] wbuf_rdata;
|
|
||||||
enum logic [3:0] {IDLE, INVALID, GADDR, GRLEN, GWDATA, AXI_AR, AXI_R, AXI_AW, AXI_W, AXI_B} stat;
|
|
||||||
wire[ 7:0] wbuf_raddr_n = stat == AXI_W && wready ? wbuf_raddr + 8'd1 : wbuf_raddr;
|
|
||||||
|
|
||||||
assign awvalid = stat == AXI_AW;
|
|
||||||
assign wvalid = stat == AXI_W;
|
|
||||||
assign wlast = wbuf_raddr == wbuf_waddr;
|
|
||||||
assign wdata = wbuf_rdata;
|
|
||||||
assign bready = stat == AXI_B;
|
|
||||||
assign arvalid = stat == AXI_AR;
|
|
||||||
|
|
||||||
always @ (posedge clk or negedge rstn)
|
|
||||||
if(~rstn) begin
|
|
||||||
awaddr <= '0;
|
|
||||||
awlen <= '0;
|
|
||||||
araddr <= '0;
|
|
||||||
arlen <= '0;
|
|
||||||
rw <= 1'b0;
|
|
||||||
value <= '0;
|
|
||||||
value_cnt <= '0;
|
|
||||||
wbuf_wen <= 1'b0;
|
|
||||||
wbuf_waddr <= '0;
|
|
||||||
wbuf_wdata <= '0;
|
|
||||||
wbuf_raddr <= '0;
|
|
||||||
stat <= IDLE;
|
|
||||||
end else begin
|
|
||||||
wbuf_wen <= 1'b0;
|
|
||||||
case(stat)
|
|
||||||
IDLE: if(rx_valid) begin
|
|
||||||
value <= '0;
|
|
||||||
value_cnt <= '0;
|
|
||||||
wbuf_raddr <= '0;
|
|
||||||
if( isW(rx_data) ) begin
|
|
||||||
rw <= 1'b0;
|
|
||||||
stat <= GADDR;
|
|
||||||
end else if( isR(rx_data) ) begin
|
|
||||||
rw <= 1'b1;
|
|
||||||
stat <= GADDR;
|
|
||||||
end else if( ~isNewline(rx_data) ) begin
|
|
||||||
stat <= INVALID;
|
|
||||||
end
|
|
||||||
end
|
|
||||||
GADDR: if(rx_valid) begin
|
|
||||||
if( isNewline(rx_data) ) begin
|
|
||||||
value <= '0;
|
|
||||||
stat <= IDLE;
|
|
||||||
end else if( isSpace(rx_data) ) begin
|
|
||||||
value <= '0;
|
|
||||||
if(rw) begin
|
|
||||||
araddr <= value[A_WIDTH-1:0];
|
|
||||||
stat <= GRLEN;
|
|
||||||
end else begin
|
|
||||||
awaddr <= value[A_WIDTH-1:0];
|
|
||||||
stat <= GWDATA;
|
|
||||||
end
|
|
||||||
end else if( isHex(rx_data) ) begin
|
|
||||||
value <= { value[V_WIDTH-5:0], getHex(rx_data) };
|
|
||||||
end else begin
|
|
||||||
stat <= INVALID;
|
|
||||||
end
|
|
||||||
end
|
|
||||||
GRLEN: if(rx_valid) begin
|
|
||||||
if( isNewline(rx_data) ) begin
|
|
||||||
value <= '0;
|
|
||||||
arlen <= value[7:0];
|
|
||||||
stat <= AXI_AR;
|
|
||||||
end else if( isHex(rx_data) ) begin
|
|
||||||
value <= { value[V_WIDTH-5:0], getHex(rx_data) };
|
|
||||||
end else begin
|
|
||||||
stat <= INVALID;
|
|
||||||
end
|
|
||||||
end
|
|
||||||
GWDATA: if(rx_valid) begin
|
|
||||||
if( isNewline(rx_data) ) begin
|
|
||||||
wbuf_wen <= 1'b1;
|
|
||||||
wbuf_waddr <= value_cnt;
|
|
||||||
wbuf_wdata <= value[D_WIDTH-1:0];
|
|
||||||
awlen <= value_cnt;
|
|
||||||
stat <= AXI_AW;
|
|
||||||
end else if( isSpace(rx_data) ) begin
|
|
||||||
value <= '0;
|
|
||||||
value_cnt <= value_cnt + 8'd1;
|
|
||||||
wbuf_wen <= 1'b1;
|
|
||||||
wbuf_waddr <= value_cnt;
|
|
||||||
wbuf_wdata <= value[D_WIDTH-1:0];
|
|
||||||
end else if( isHex(rx_data) ) begin
|
|
||||||
value <= { value[V_WIDTH-5:0], getHex(rx_data) };
|
|
||||||
end else begin
|
|
||||||
stat <= INVALID;
|
|
||||||
end
|
|
||||||
end
|
|
||||||
INVALID: if( rx_valid ) begin
|
|
||||||
if ( isNewline(rx_data) )
|
|
||||||
stat <= IDLE;
|
|
||||||
end
|
|
||||||
AXI_AR: if(arready) begin
|
|
||||||
stat <= AXI_R;
|
|
||||||
end
|
|
||||||
AXI_R: if(rvalid & rready & rlast) begin
|
|
||||||
stat <= IDLE;
|
|
||||||
end
|
|
||||||
AXI_AW: if(awready) begin
|
|
||||||
stat <= AXI_W;
|
|
||||||
end
|
|
||||||
AXI_W: if(wready) begin
|
|
||||||
wbuf_raddr <= wbuf_raddr + 8'd1;
|
|
||||||
if(wbuf_raddr==awlen)
|
|
||||||
stat <= AXI_B;
|
|
||||||
end
|
|
||||||
AXI_B: if(bvalid) begin
|
|
||||||
stat <= IDLE;
|
|
||||||
end
|
|
||||||
default: stat<=IDLE;
|
|
||||||
endcase
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
logic [D_WIDTH-1:0] mem_for_axi4write [256];
|
|
||||||
|
|
||||||
always @ (posedge clk)
|
|
||||||
wbuf_rdata <= mem_for_axi4write[wbuf_raddr_n];
|
|
||||||
|
|
||||||
always @ (posedge clk)
|
|
||||||
if(wbuf_wen)
|
|
||||||
mem_for_axi4write[wbuf_waddr] <= wbuf_wdata;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
localparam CLK_DIV = 162;
|
|
||||||
localparam CLK_PART = 6;
|
|
||||||
|
|
||||||
reg uart_rx_done = 1'b0;
|
|
||||||
reg [ 7:0] uart_rx_data = 8'h0;
|
|
||||||
reg [ 2:0] uart_rx_supercnt=3'h0;
|
|
||||||
reg [31:0] uart_rx_cnt = 0;
|
|
||||||
reg [ 7:0] uart_rx_databuf = 8'h0;
|
|
||||||
reg [ 5:0] uart_rx_status=6'h0, uart_rx_shift=6'h0;
|
|
||||||
reg uart_rxr=1'b1;
|
|
||||||
wire recvbit = (uart_rx_shift[1]&uart_rx_shift[0]) | (uart_rx_shift[0]&uart_rxr) | (uart_rxr&uart_rx_shift[1]) ;
|
|
||||||
wire [2:0] supercntreverse = {uart_rx_supercnt[0], uart_rx_supercnt[1], uart_rx_supercnt[2]};
|
|
||||||
|
|
||||||
assign rx_valid = uart_rx_done;
|
|
||||||
assign rx_data = uart_rx_data;
|
|
||||||
|
|
||||||
always @ (posedge clk or negedge rstn)
|
|
||||||
if(~rstn)
|
|
||||||
uart_rxr <= 1'b1;
|
|
||||||
else
|
|
||||||
uart_rxr <= uart_rx;
|
|
||||||
|
|
||||||
always @ (posedge clk or negedge rstn)
|
|
||||||
if(~rstn) begin
|
|
||||||
uart_rx_done <= 1'b0;
|
|
||||||
uart_rx_data <= 8'h0;
|
|
||||||
uart_rx_supercnt<= 3'h0;
|
|
||||||
uart_rx_status <= 6'h0;
|
|
||||||
uart_rx_shift <= 6'h0;
|
|
||||||
uart_rx_databuf <= 8'h0;
|
|
||||||
uart_rx_cnt <= 0;
|
|
||||||
end else begin
|
|
||||||
uart_rx_done <= 1'b0;
|
|
||||||
if( (supercntreverse<CLK_PART) ? (uart_rx_cnt>=CLK_DIV) : (uart_rx_cnt>=CLK_DIV-1) ) begin
|
|
||||||
if(uart_rx_status==0) begin
|
|
||||||
if(uart_rx_shift == 6'b111_000)
|
|
||||||
uart_rx_status <= 1;
|
|
||||||
end else begin
|
|
||||||
if(uart_rx_status[5] == 1'b0) begin
|
|
||||||
if(uart_rx_status[1:0] == 2'b11)
|
|
||||||
uart_rx_databuf <= {recvbit, uart_rx_databuf[7:1]};
|
|
||||||
uart_rx_status <= uart_rx_status + 5'b1;
|
|
||||||
end else begin
|
|
||||||
if(uart_rx_status<62) begin
|
|
||||||
uart_rx_status <= 62;
|
|
||||||
uart_rx_data <= uart_rx_databuf;
|
|
||||||
uart_rx_done <= 1'b1;
|
|
||||||
end else begin
|
|
||||||
uart_rx_status <= uart_rx_status + 6'd1;
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
uart_rx_shift <= {uart_rx_shift[4:0], uart_rxr};
|
|
||||||
uart_rx_supercnt <= uart_rx_supercnt + 3'h1;
|
|
||||||
uart_rx_cnt <= 0;
|
|
||||||
end else
|
|
||||||
uart_rx_cnt <= uart_rx_cnt + 1;
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
axis2uarttx #(
|
|
||||||
.CLK_DIV ( 651 ),
|
|
||||||
.DATA_WIDTH ( D_WIDTH ),
|
|
||||||
.FIFO_ASIZE ( 10 )
|
|
||||||
) uart_tx_i (
|
|
||||||
.rstn ( rstn ),
|
|
||||||
.clk ( clk ),
|
|
||||||
.tvalid ( rvalid ),
|
|
||||||
.tready ( rready ),
|
|
||||||
.tlast ( rlast ),
|
|
||||||
.tdata ( rdata ),
|
|
||||||
.uart_tx ( uart_tx )
|
|
||||||
);
|
|
||||||
|
|
||||||
endmodule
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
module axis2uarttx #(
|
|
||||||
parameter CLK_DIV = 434,
|
|
||||||
parameter DATA_WIDTH = 32,
|
|
||||||
parameter FIFO_ASIZE = 8
|
|
||||||
) (
|
|
||||||
// AXI-stream (slave) side
|
|
||||||
input logic rstn,
|
|
||||||
input logic clk,
|
|
||||||
input logic tvalid,
|
|
||||||
input logic tlast,
|
|
||||||
output logic tready,
|
|
||||||
input logic [DATA_WIDTH-1:0] tdata,
|
|
||||||
// UART TX signal
|
|
||||||
output logic uart_tx
|
|
||||||
);
|
|
||||||
localparam TX_WIDTH = (DATA_WIDTH+3) / 4;
|
|
||||||
|
|
||||||
function automatic logic [7:0] hex2ascii (input [3:0] hex);
|
|
||||||
return {4'h3, hex} + ((hex<4'hA) ? 8'h0 : 8'h7) ;
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
logic uart_txb;
|
|
||||||
logic [FIFO_ASIZE-1:0] fifo_rpt='0, fifo_wpt='0;
|
|
||||||
wire [FIFO_ASIZE-1:0] fifo_wpt_next = fifo_wpt + {{(FIFO_ASIZE-1){1'b0}}, 1'b1};
|
|
||||||
wire [FIFO_ASIZE-1:0] fifo_rpt_next = fifo_rpt + {{(FIFO_ASIZE-1){1'b0}}, 1'b1};
|
|
||||||
logic [31:0] cyccnt=0, hexcnt=0, txcnt=0;
|
|
||||||
logic [ 7:0] txshift = '1;
|
|
||||||
logic fifo_tlast;
|
|
||||||
logic [DATA_WIDTH-1:0] fifo_data;
|
|
||||||
logic endofline = 1'b0;
|
|
||||||
logic [TX_WIDTH*4-1:0] data='0;
|
|
||||||
wire emptyn = (fifo_rpt != fifo_wpt);
|
|
||||||
assign tready = (fifo_rpt != fifo_wpt_next) & rstn;
|
|
||||||
|
|
||||||
always @ (posedge clk or negedge rstn)
|
|
||||||
if(~rstn)
|
|
||||||
uart_tx <= 1'b1;
|
|
||||||
else begin
|
|
||||||
uart_tx <= uart_txb;
|
|
||||||
end
|
|
||||||
|
|
||||||
always @ (posedge clk or negedge rstn)
|
|
||||||
if(~rstn)
|
|
||||||
fifo_wpt <= '0;
|
|
||||||
else begin
|
|
||||||
if(tvalid & tready) fifo_wpt <= fifo_wpt_next;
|
|
||||||
end
|
|
||||||
|
|
||||||
always @ (posedge clk or negedge rstn)
|
|
||||||
if(~rstn)
|
|
||||||
cyccnt <= 0;
|
|
||||||
else
|
|
||||||
cyccnt <= (cyccnt<CLK_DIV-1) ? cyccnt+1 : 0;
|
|
||||||
|
|
||||||
always @ (posedge clk or negedge rstn)
|
|
||||||
if(~rstn) begin
|
|
||||||
fifo_rpt <= '0;
|
|
||||||
endofline <= 1'b0;
|
|
||||||
data <= '0;
|
|
||||||
uart_txb <= 1'b1;
|
|
||||||
txshift <= '1;
|
|
||||||
txcnt <= 0;
|
|
||||||
hexcnt <= 0;
|
|
||||||
end else begin
|
|
||||||
if( hexcnt>(1+TX_WIDTH) ) begin
|
|
||||||
uart_txb <= 1'b1;
|
|
||||||
endofline <= fifo_tlast;
|
|
||||||
data <= '0;
|
|
||||||
data[DATA_WIDTH-1:0] <= fifo_data;
|
|
||||||
hexcnt <= hexcnt-1;
|
|
||||||
end else if(hexcnt>0 || txcnt>0) begin
|
|
||||||
if(cyccnt==CLK_DIV-1) begin
|
|
||||||
if(txcnt>0) begin
|
|
||||||
{txshift, uart_txb} <= {1'b1, txshift};
|
|
||||||
txcnt <= txcnt-1;
|
|
||||||
end else begin
|
|
||||||
uart_txb <= 1'b0;
|
|
||||||
hexcnt <= hexcnt-1;
|
|
||||||
if(hexcnt>1)
|
|
||||||
txshift <= hex2ascii(data[(hexcnt-2)*4+:4]);
|
|
||||||
else if(endofline)
|
|
||||||
txshift <= 8'h0A;
|
|
||||||
else
|
|
||||||
txshift <= 8'h20;
|
|
||||||
txcnt <= 11;
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end else if(emptyn) begin
|
|
||||||
uart_txb <= 1'b1;
|
|
||||||
hexcnt <= 2 + TX_WIDTH;
|
|
||||||
txcnt <= 0;
|
|
||||||
fifo_rpt <= fifo_rpt_next;
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
logic [DATA_WIDTH:0] mem_for_axi_stream_to_uart_tx_fifo [1<<FIFO_ASIZE];
|
|
||||||
|
|
||||||
always @ (posedge clk)
|
|
||||||
{fifo_tlast, fifo_data} <= mem_for_axi_stream_to_uart_tx_fifo[fifo_rpt];
|
|
||||||
|
|
||||||
always @ (posedge clk)
|
|
||||||
if(tvalid & tready)
|
|
||||||
mem_for_axi_stream_to_uart_tx_fifo[fifo_wpt] <= {tlast, tdata};
|
|
||||||
|
|
||||||
endmodule
|
|
Binary file not shown.
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 8.6 KiB |
Loading…
x
Reference in New Issue
Block a user