change to Verilog2001

This commit is contained in:
WangXuan95 2023-06-06 19:52:19 +08:00
parent 6b9791c1fb
commit ffa1fe0414
17 changed files with 1645 additions and 1036 deletions

945
README.md

File diff suppressed because it is too large Load Diff

View File

@ -2,8 +2,8 @@
//--------------------------------------------------------------------------------------------------------
// Module : ddr_sdram_ctrl
// Type : synthesizable, IP's top
// Standard: SystemVerilog 2005 (IEEE1800-2005)
// Function: DDR-SDRAM (DDR1) controller
// Standard: Verilog 2001 (IEEE1364-2001)
// Function: DDR1 SDRAM controller
// with AXI4 interface
//--------------------------------------------------------------------------------------------------------
@ -59,18 +59,32 @@ module ddr_sdram_ctrl #(
inout [ (4<<DQ_LEVEL)-1:0] ddr_dq
);
localparam DQS_BITS = ((1<<DQ_LEVEL)+1)/2;
reg clk2 = '0;
reg init_done = '0;
reg [2:0] ref_idle = 3'd1, ref_real = '0;
reg [9:0] ref_cnt = '0;
reg [7:0] cnt = '0;
enum logic [3:0] {RESET, IDLE, CLEARDLL, REFRESH, WPRE, WRITE, WRESP, WWAIT, RPRE, READ, RRESP, RWAIT} stat = RESET;
reg clk2 = 1'b0;
reg init_done = 1'b0;
reg [2:0] ref_idle = 3'd1, ref_real = 3'd0;
reg [9:0] ref_cnt = 10'd0;
reg [7:0] cnt = 8'd0;
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;
reg [COL_BITS-2:0] col_addr = '0;
reg [COL_BITS-2:0] col_addr = 0;
wire [ROW_BITS-1:0] ddr_a_col;
generate if(COL_BITS>10) begin
@ -80,69 +94,70 @@ end else begin
end endgenerate
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 [(4<<DQ_LEVEL)-1:0] o_dh_a = '0;
reg [(4<<DQ_LEVEL)-1:0] o_dl_a = '0;
reg o_v_b = '0;
reg [(4<<DQ_LEVEL)-1:0] o_dh_b = '0;
reg o_dqs_c = '0;
reg [(4<<DQ_LEVEL)-1:0] o_d_c = '0;
reg [(4<<DQ_LEVEL)-1:0] o_d_d = '0;
reg o_v_a = 1'b0;
reg [(4<<DQ_LEVEL)-1:0] o_dh_a = 0;
reg [(4<<DQ_LEVEL)-1:0] o_dl_a = 0;
reg o_v_b = 1'b0;
reg [(4<<DQ_LEVEL)-1:0] o_dh_b = 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_d = 0;
reg i_v_a = '0;
reg i_l_a = '0;
reg i_v_b = '0;
reg i_l_b = '0;
reg i_v_c = '0;
reg i_l_c = '0;
reg i_dqs_c = '0;
reg [(4<<DQ_LEVEL)-1:0] i_d_c = '0;
reg i_v_d = '0;
reg i_l_d = '0;
reg [(8<<DQ_LEVEL)-1:0] i_d_d = '0;
reg i_v_e = '0;
reg i_l_e = '0;
reg [(8<<DQ_LEVEL)-1:0] i_d_e = '0;
reg i_v_a = 1'b0;
reg i_l_a = 1'b0;
reg i_v_b = 1'b0;
reg i_l_b = 1'b0;
reg i_v_c = 1'b0;
reg i_l_c = 1'b0;
reg i_dqs_c = 1'b0;
reg [(4<<DQ_LEVEL)-1:0] i_d_c = 0;
reg i_v_d = 1'b0;
reg i_l_d = 1'b0;
reg [(8<<DQ_LEVEL)-1:0] i_d_d = 0;
reg i_v_e = 1'b0;
reg i_l_e = 1'b0;
reg [(8<<DQ_LEVEL)-1:0] i_d_e = 0;
// -------------------------------------------------------------------------------------
// constants defination and assignment
// -------------------------------------------------------------------------------------
localparam [ROW_BITS-1:0] DDR_A_DEFAULT = (ROW_BITS)'('b0100_0000_0000);
localparam [ROW_BITS-1:0] DDR_A_MR0 = (ROW_BITS)'('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_DEFAULT = 'b0100_0000_0000;
localparam [ROW_BITS-1:0] DDR_A_MR0 = 'b0001_0010_1001;
localparam [ROW_BITS-1:0] DDR_A_MR_CLEAR_DLL = 'b0000_0010_1001;
initial ddr_cs_n = 1'b1;
initial ddr_ras_n = 1'b1;
initial ddr_cas_n = 1'b1;
initial ddr_we_n = 1'b1;
initial ddr_ba = '0;
initial ddr_ba = 0;
initial ddr_a = DDR_A_DEFAULT;
initial {rstn, clk} = '0;
initial rstn = 1'b0;
initial clk = 1'b0;
// -------------------------------------------------------------------------------------
// generate reset sync with drv_clk
// -------------------------------------------------------------------------------------
reg rstn_clk = '0;
reg [2:0] rstn_clk_l = '0;
reg rstn_clk = 1'b0;
reg [2:0] rstn_clk_l = 3'b0;
always @ (posedge drv_clk or negedge rstn_async)
if(~rstn_async)
{rstn_clk, rstn_clk_l} <= '0;
{rstn_clk, rstn_clk_l} <= 4'b0;
else
{rstn_clk, rstn_clk_l} <= {rstn_clk_l, 1'b1};
// -------------------------------------------------------------------------------------
// generate reset sync with clk
// -------------------------------------------------------------------------------------
reg rstn_aclk = '0;
reg [2:0] rstn_aclk_l = '0;
reg rstn_aclk = 1'b0;
reg [2:0] rstn_aclk_l = 3'b0;
always @ (posedge clk or negedge rstn_async)
if(~rstn_async)
{rstn_aclk, rstn_aclk_l} <= '0;
{rstn_aclk, rstn_aclk_l} <= 4'b0;
else
{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)
if(~rstn_aclk) begin
ref_cnt <= '0;
ref_cnt <= 10'd0;
ref_idle <= 3'd1;
end else begin
if(init_done) begin
if(ref_cnt<tREFC) begin
ref_cnt <= ref_cnt + 10'd1;
end else begin
ref_cnt <= '0;
ref_cnt <= 10'd0;
ref_idle <= ref_idle + 3'd1;
end
end
@ -192,16 +207,16 @@ assign ddr_cke = ~ddr_cs_n;
// -------------------------------------------------------------------------------------
// generate DDR DQ output behavior
// -------------------------------------------------------------------------------------
assign ddr_dm = output_enable ? '0 : 'z;
assign ddr_dqs = output_enable ? {DQS_BITS{o_dqs_c}} : 'z;
assign ddr_dq = output_enable ? o_d_d : 'z;
assign ddr_dm = output_enable ? {DQS_BITS{1'b0}} : {DQS_BITS{1'bz}};
assign ddr_dqs = output_enable ? {DQS_BITS{o_dqs_c}} : {DQS_BITS{1'bz}};
assign ddr_dq = output_enable ? o_d_d : {(4<<DQ_LEVEL){1'bz}};
// -------------------------------------------------------------------------------------
// assignment for user interface (AXI4)
// -------------------------------------------------------------------------------------
assign awready = stat==IDLE && init_done && ref_real==ref_idle;
assign wready = stat==WRITE;
assign bvalid = stat==WRESP;
assign wready = stat==WRITE;
assign bvalid = stat==WRESP;
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_cas_n <= 1'b1;
ddr_we_n <= 1'b1;
ddr_ba <= '0;
ddr_ba <= 0;
ddr_a <= DDR_A_DEFAULT;
col_addr <= '0;
burst_len <= '0;
col_addr <= 0;
burst_len <= 8'd0;
init_done <= 1'b0;
ref_real <= 3'd0;
cnt <= 8'd0;
@ -238,10 +253,10 @@ always @ (posedge clk or negedge rstn_aclk)
ddr_ras_n <= 1'b0;
ddr_cas_n <= 1'b0;
ddr_we_n <= 1'b0;
ddr_ba <= 'h1;
ddr_a <= '0;
ddr_ba <= 1;
ddr_a <= 0;
end else begin
ddr_ba <= '0;
ddr_ba <= 0;
ddr_a <= DDR_A_MR0;
stat <= IDLE;
end
@ -250,7 +265,7 @@ always @ (posedge clk or negedge rstn_aclk)
ddr_ras_n <= 1'b1;
ddr_cas_n <= 1'b1;
ddr_we_n <= 1'b1;
ddr_ba <= '0;
ddr_ba <= 0;
ddr_a <= DDR_A_DEFAULT;
cnt <= 8'd0;
if(ref_real != ref_idle) begin
@ -317,7 +332,7 @@ always @ (posedge clk or negedge rstn_aclk)
ddr_we_n <= 1'b0;
col_addr <= col_addr + {{(COL_BITS-2){1'b0}}, 1'b1};
if(burst_last | wlast) begin
cnt <= '0;
cnt <= 8'd0;
stat <= WRESP;
end else begin
cnt <= cnt + 8'd1;
@ -349,7 +364,7 @@ always @ (posedge clk or negedge rstn_aclk)
ddr_a <= ddr_a_col;
col_addr <= col_addr + {{(COL_BITS-2){1'b0}}, 1'b1};
if(burst_last) begin
cnt <= '0;
cnt <= 8'd0;
stat <= RRESP;
end else begin
cnt <= cnt + 8'd1;
@ -390,7 +405,7 @@ always @ (posedge clk or negedge rstn)
always @ (posedge clk or negedge rstn)
if(~rstn) begin
o_v_a <= 1'b0;
{o_dh_a, o_dl_a} <= '0;
{o_dh_a, o_dl_a} <= 0;
end else begin
o_v_a <= (stat==WRITE && wvalid);
{o_dh_a, o_dl_a} <= wdata;
@ -402,7 +417,7 @@ always @ (posedge clk or negedge rstn)
always @ (posedge clk or negedge rstn)
if(~rstn) begin
o_v_b <= 1'b0;
o_dh_b <= '0;
o_dh_b <= 0;
end else begin
o_v_b <= o_v_a;
o_dh_b <= o_dh_a;
@ -412,12 +427,18 @@ always @ (posedge clk or negedge rstn)
// dq and dqs generate for output (write)
// -------------------------------------------------------------------------------------
always @ (posedge clk2)
if(~clk) begin
if (~clk) begin
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
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
// -------------------------------------------------------------------------------------
@ -440,8 +461,8 @@ always @ (posedge clk2)
always @ (posedge clk or negedge rstn)
if(~rstn) begin
{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_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;
end else begin
i_v_a <= stat==READ ? 1'b1 : 1'b0;
i_l_a <= burst_last;
@ -457,7 +478,7 @@ always @ (posedge clk or negedge rstn)
if(~rstn) begin
i_v_e <= 1'b0;
i_l_e <= 1'b0;
i_d_e <= '0;
i_d_e <= 0;
end else begin
i_v_e <= i_v_d;
i_l_e <= i_l_d;
@ -472,16 +493,18 @@ generate if(READ_BUFFER) begin
localparam AWIDTH = 10;
localparam DWIDTH = 1 + (8<<DQ_LEVEL);
reg [AWIDTH-1:0] wpt = '0, rpt = '0;
reg dvalid = '0, valid = '0;
reg [DWIDTH-1:0] datareg = '0;
reg [AWIDTH-1:0] wpt = 0, rpt = 0;
reg dvalid = 1'b0, valid = 1'b0;
reg [DWIDTH-1:0] datareg = 0;
wire rreq;
reg [DWIDTH-1:0] fifo_rdata;
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 rreq = emptyn & ( rready | ~rvalid );
assign {rlast, rdata} = dvalid ? fifo_rdata : datareg;
@ -490,13 +513,13 @@ generate if(READ_BUFFER) begin
if(~rstn)
wpt <= 0;
else if(i_v_e & itready)
wpt <= wpt + (AWIDTH)'(1);
wpt <= wpt + AW_ONE;
always @ (posedge clk or negedge rstn)
if(~rstn)
rpt <= 0;
else if(rreq & emptyn)
rpt <= rpt + (AWIDTH)'(1);
rpt <= rpt + AW_ONE;
always @ (posedge clk or negedge rstn)
if(~rstn) begin

View File

@ -2,7 +2,7 @@
//--------------------------------------------------------------------------------------------------------
// Module : axi_self_test_master
// Type : synthesizable
// Standard: SystemVerilog 2005 (IEEE1800-2005)
// Standard: Verilog 2001 (IEEE1364-2001)
// Function: write increase data to AXI4 slave,
// then read data and check whether they are increasing
//--------------------------------------------------------------------------------------------------------
@ -39,13 +39,22 @@ module axi_self_test_master #(
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;
reg awaddr_carry = '0;
reg [7:0] w_cnt = '0;
enum logic [2:0] {INIT, AW, W, B, AR, R} stat = INIT;
reg awaddr_carry = 1'b0;
reg [7:0] w_cnt = 8'd0;
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)
assign aw_end = awaddr[A_WIDTH_TEST];
@ -57,26 +66,27 @@ assign awvalid = stat==AW;
assign awlen = WBURST_LEN;
assign wvalid = stat==W;
assign wlast = w_cnt==WBURST_LEN;
assign wdata = (D_WIDTH)'(awaddr);
assign wdata = awaddr;
assign bready = 1'b1;
assign arvalid = stat==AR;
assign arlen = RBURST_LEN;
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)
if(~rstn) begin
{awaddr_carry, awaddr} <= '0;
{awaddr_carry, awaddr} <= 0;
w_cnt <= 8'd0;
araddr <= '0;
araddr <= 0;
stat <= INIT;
end else begin
case(stat)
INIT: begin
{awaddr_carry, awaddr} <= '0;
{awaddr_carry, awaddr} <= 0;
w_cnt <= 8'd0;
araddr <= '0;
araddr <= 0;
stat <= AW;
end
AW: if(awready) begin
@ -84,7 +94,7 @@ always @ (posedge clk or negedge rstn)
stat <= W;
end
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;
if(wlast)
stat <= B;
@ -100,7 +110,7 @@ always @ (posedge clk or negedge rstn)
if(rlast) begin
stat <= AR;
if(araddr_next[A_WIDTH_TEST])
araddr <= '0;
araddr <= 0;
end
end
endcase
@ -109,7 +119,8 @@ always @ (posedge clk or negedge rstn)
// ------------------------------------------------------------
// 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)
if(~rstn) begin
error <= 1'b0;

View File

@ -2,7 +2,7 @@
//--------------------------------------------------------------------------------------------------------
// Module : tb_ddr_sdram_ctrl
// Type : simulation, top
// Standard: SystemVerilog 2005 (IEEE1800-2005)
// Standard: Verilog 2001 (IEEE1364-2001)
// Function: testbench for ddr_sdram_ctrl
//--------------------------------------------------------------------------------------------------------

View File

@ -1,5 +1,5 @@
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
del sim.out
pause

File diff suppressed because one or more lines are too long

View File

@ -2,7 +2,7 @@
//--------------------------------------------------------------------------------------------------------
// Module : axi_self_test_master
// Type : synthesizable
// Standard: SystemVerilog 2005 (IEEE1800-2005)
// Standard: Verilog 2001 (IEEE1364-2001)
// Function: write increase data to AXI4 slave,
// then read data and check whether they are increasing
//--------------------------------------------------------------------------------------------------------
@ -39,13 +39,22 @@ module axi_self_test_master #(
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;
reg awaddr_carry = '0;
reg [7:0] w_cnt = '0;
enum logic [2:0] {INIT, AW, W, B, AR, R} stat = INIT;
reg awaddr_carry = 1'b0;
reg [7:0] w_cnt = 8'd0;
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)
assign aw_end = awaddr[A_WIDTH_TEST];
@ -57,26 +66,27 @@ assign awvalid = stat==AW;
assign awlen = WBURST_LEN;
assign wvalid = stat==W;
assign wlast = w_cnt==WBURST_LEN;
assign wdata = (D_WIDTH)'(awaddr);
assign wdata = awaddr;
assign bready = 1'b1;
assign arvalid = stat==AR;
assign arlen = RBURST_LEN;
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)
if(~rstn) begin
{awaddr_carry, awaddr} <= '0;
{awaddr_carry, awaddr} <= 0;
w_cnt <= 8'd0;
araddr <= '0;
araddr <= 0;
stat <= INIT;
end else begin
case(stat)
INIT: begin
{awaddr_carry, awaddr} <= '0;
{awaddr_carry, awaddr} <= 0;
w_cnt <= 8'd0;
araddr <= '0;
araddr <= 0;
stat <= AW;
end
AW: if(awready) begin
@ -84,7 +94,7 @@ always @ (posedge clk or negedge rstn)
stat <= W;
end
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;
if(wlast)
stat <= B;
@ -100,7 +110,7 @@ always @ (posedge clk or negedge rstn)
if(rlast) begin
stat <= AR;
if(araddr_next[A_WIDTH_TEST])
araddr <= '0;
araddr <= 0;
end
end
endcase
@ -109,7 +119,8 @@ always @ (posedge clk or negedge rstn)
// ------------------------------------------------------------
// 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)
if(~rstn) begin
error <= 1'b0;

View File

@ -38,10 +38,10 @@
set_global_assignment -name FAMILY "Cyclone IV E"
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 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 MIN_CORE_JUNCTION_TEMP 0
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_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 USE_SIGNALTAP_FILE SignalTap/stp1.stp
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_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 SYSTEMVERILOG_FILE axi_self_test_master.sv
set_global_assignment -name SYSTEMVERILOG_FILE ../RTL/ddr_sdram_ctrl.sv
set_global_assignment -name VERILOG_FILE fpga_top.v
set_global_assignment -name VERILOG_FILE axi_self_test_master.v
set_global_assignment -name VERILOG_FILE ../RTL/ddr_sdram_ctrl.v
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
@ -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[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_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_instance_assignment -name POST_FIT_CONNECT_TO_SLD_NODE_ENTITY_PORT crc[0] -to auto_signaltap_0|vcc -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_instance_assignment -name POST_FIT_CONNECT_TO_SLD_NODE_ENTITY_PORT crc[2] -to auto_signaltap_0|vcc -section_id auto_signaltap_0
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_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_NODE_PARAMETER_ASSIGNMENT "SLD_NODE_CRC_LOWORD=45013" -section_id auto_signaltap_0
set_global_assignment -name SLD_NODE_PARAMETER_ASSIGNMENT "SLD_NODE_CRC_HIWORD=22477" -section_id auto_signaltap_0
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 SLD_FILE db/stp1_auto_stripped.stp
set_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top

View File

@ -1,14 +1,14 @@
//--------------------------------------------------------------------------------------------------------
// Module : top
// Module : fpga_top
// 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,
// write increase data to DDR,
// then read data and check whether they are increasing
//--------------------------------------------------------------------------------------------------------
module top (
module fpga_top (
input wire clk50m,
output wire ddr_ck_p, ddr_ck_n,

View File

@ -38,10 +38,10 @@
set_global_assignment -name FAMILY "Cyclone IV E"
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 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 MIN_CORE_JUNCTION_TEMP 0
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 STRATIX_DEVICE_IO_STANDARD "2.5 V"
set_global_assignment -name SYSTEMVERILOG_FILE top.sv
set_global_assignment -name SYSTEMVERILOG_FILE uart2axi4.sv
set_global_assignment -name SYSTEMVERILOG_FILE ../RTL/ddr_sdram_ctrl.sv
set_global_assignment -name VERILOG_FILE fpga_top.v
set_global_assignment -name VERILOG_FILE uart/uart2axi4.v
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
@ -92,7 +94,8 @@ set_location_assignment PIN_74 -to ddr_dq[6]
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_FITTER_PRESERVATION_LEVEL PLACEMENT_AND_ROUTING -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

View File

@ -1,13 +1,13 @@
//--------------------------------------------------------------------------------------------------------
// Module : top
// Module : fpga_top
// 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,
// use UART command to read/write DDR
//--------------------------------------------------------------------------------------------------------
module top (
module fpga_top (
input wire clk50m,
output wire uart_tx,
@ -23,6 +23,7 @@ module top (
inout [ 7:0] ddr_dq
);
// -------------------------------------------------------------------------------------
// DDR-SDRAM parameters
// -------------------------------------------------------------------------------------
@ -82,10 +83,15 @@ defparam altpll_i.bandwidth_type = "AUTO", altpll_i.clk0_divide_by = 1, altpl
// AXI4 master for testing
// -------------------------------------------------------------------------------------
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 )
) uart_axi_i (
) u_uart2axi4 (
.rstn ( rstn ),
.clk ( clk ),
// AXI4 master ----------------------
.awvalid ( awvalid ),
.awready ( awready ),
.awaddr ( awaddr ),
@ -104,8 +110,9 @@ uart2axi4 #(
.rready ( rready ),
.rlast ( rlast ),
.rdata ( rdata ),
.uart_tx ( uart_tx ),
.uart_rx ( uart_rx )
// UART ----------------------
.i_uart_rx ( uart_rx ),
.o_uart_tx ( uart_tx )
);
@ -121,7 +128,7 @@ ddr_sdram_ctrl #(
.tREFC ( 10'd512 ),
.tW2I ( 8'd7 ),
.tR2I ( 8'd7 )
) ddr_ctrl_i(
) u_ddr_ctrl (
.rstn_async ( locked ),
.drv_clk ( clk300m ),
.rstn ( rstn ),

View 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

View 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

View 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

View File

@ -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