mirror of
https://github.com/WangXuan95/FPGA-DDR-SDRAM.git
synced 2025-01-17 20:02:52 +08:00
change to Verilog2001
This commit is contained in:
parent
6b9791c1fb
commit
ffa1fe0414
@ -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
|
@ -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;
|
@ -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
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
|
@ -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
@ -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;
|
@ -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
|
@ -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,
|
@ -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
|
@ -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 ),
|
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