Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Configurable UART #57

Draft
wants to merge 7 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion ibex_demo_system_core.core
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,13 @@ filesets:
- rtl/system/gpio.sv
- rtl/system/pwm.sv
- rtl/system/pwm_wrapper.sv
- rtl/system/uart.sv
- rtl/system/uart_top.v
- rtl/system/uart_rx.v
- rtl/system/uart_tx.v
- rtl/system/sync_fifo.v
- rtl/system/async_fifo.v
- rtl/system/uart.vh
- rtl/system/synchronizer.v
- rtl/system/spi_host.sv
- rtl/system/spi_top.sv
file_type: systemVerilogSource
Expand Down
101 changes: 101 additions & 0 deletions rtl/system/async_fifo.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
`include "synchronizer.v"
`timescale 1ns/1ps
module async_fifo #(
parameter WIDTH = 32, // width of data bus
parameter DEPTH = 16 // depth of FIFO buffer
) (
input wire [WIDTH-1:0] wdata_i,
input wire wclk_i,
input wire rclk_i,
input wire rst_ni,
input wire we_i,
input wire re_i,
output wire [WIDTH-1:0] rdata_o,
output wire full_o,
output wire empty_o,
output wire near_full_o,
output wire near_empty_o
);

localparam ADDR_BITS = $clog2(DEPTH); // address width for buffer

reg [ADDR_BITS:0] w_ptr, r_ptr;
wire [ADDR_BITS:0] w_ptr_gray, r_ptr_gray;

wire [ADDR_BITS:0] w_ptr_next, r_ptr_next;
wire [ADDR_BITS:0] w_ptr_next_gray, r_ptr_next_gray;

wire [ADDR_BITS-1:0] w_addr, r_addr;

wire [ADDR_BITS:0] w_ptr_sync_gray, r_ptr_sync_gray;
reg [ADDR_BITS:0] w_ptr_sync_bin, r_ptr_sync_bin;

reg [WIDTH-1:0] mem [0:DEPTH-1];

assign w_ptr_next = (we_i & ~full_o)? w_ptr + 1'b1 : w_ptr;
assign r_ptr_next = (re_i & ~empty_o)? r_ptr + 1'b1 : r_ptr;

assign w_addr = w_ptr[ADDR_BITS-1:0];
assign r_addr = r_ptr[ADDR_BITS-1:0];

assign w_ptr_gray = w_ptr ^ (w_ptr >> 1);
assign r_ptr_gray = r_ptr ^ (r_ptr >> 1);

assign w_ptr_next_gray = w_ptr_next ^ (w_ptr_next >> 1);
assign r_ptr_next_gray = r_ptr_next ^ (r_ptr_next >> 1);

sync_reg #(
.WIDTH(ADDR_BITS+1)
) sync_w2r_w_ptr (
.clk_i(rclk_i),
.rst_ni(rst_ni),
.wdata_i(w_ptr_gray),
.rdata_o(w_ptr_sync_gray)
);

sync_reg #(
.WIDTH(ADDR_BITS+1)
) sync_r2w_r_ptr (
.clk_i(wclk_i),
.rst_ni(rst_ni),
.wdata_i(r_ptr_gray),
.rdata_o(r_ptr_sync_gray)
);

integer i;
always @(*) begin : gray_to_bin_w_ptr
for(i=0; i<ADDR_BITS+1; i = i+1)
w_ptr_sync_bin[i] = ^(w_ptr_sync_gray >> i);
end

always @(*) begin : gray_to_bin_r_ptr
for(i=0; i<ADDR_BITS+1; i = i+1)
r_ptr_sync_bin[i] = ^(r_ptr_sync_gray >> i);
end

always @(posedge wclk_i, negedge rst_ni)
if(~rst_ni)
w_ptr <= {ADDR_BITS+1{1'b0}};
else
w_ptr <= w_ptr_next;

always @(posedge wclk_i, negedge rst_ni) begin : write
if(we_i & ~full_o)
mem[w_addr] <= wdata_i;
end

always @(posedge rclk_i, negedge rst_ni) begin : read
if(~rst_ni)
r_ptr <= {ADDR_BITS+1{1'b0}};
else
r_ptr <= r_ptr_next;
end

assign full_o = w_ptr == {~r_ptr_sync_bin[ADDR_BITS], r_ptr_sync_bin[ADDR_BITS-1:0]};
assign empty_o = r_ptr == w_ptr_sync_bin;
assign rdata_o = (empty_o)? {WIDTH{1'b0}} : mem[r_addr];

assign near_full_o = 1'b0;
assign near_empty_o = 1'b0;

endmodule
38 changes: 20 additions & 18 deletions rtl/system/ibex_demo_system.sv
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ module ibex_demo_system #(

// interrupts
logic timer_irq;
logic uart_irq;
logic [1:0] uart_irq;

// host and device signals
logic host_req [NrHosts];
Expand Down Expand Up @@ -268,7 +268,7 @@ module ibex_demo_system #(
.irq_software_i(1'b0),
.irq_timer_i (timer_irq),
.irq_external_i(1'b0),
.irq_fast_i ({14'b0, uart_irq}),
.irq_fast_i ({13'b0, uart_irq}),
.irq_nm_i (1'b0),

.scramble_key_valid_i('0),
Expand Down Expand Up @@ -349,23 +349,25 @@ module ibex_demo_system #(
.pwm_o
);

uart #(
.ClockFrequency ( 50_000_000 )
uart_top #(
.CLOCK_FREQUENCY (50_000_000),
.RX_FIFO_DEPTH (16),
.TX_FIFO_DEPTH (16)
) u_uart (
.clk_i (clk_sys_i),
.rst_ni (rst_sys_ni),

.device_req_i (device_req[Uart]),
.device_addr_i (device_addr[Uart]),
.device_we_i (device_we[Uart]),
.device_be_i (device_be[Uart]),
.device_wdata_i (device_wdata[Uart]),
.device_rvalid_o(device_rvalid[Uart]),
.device_rdata_o (device_rdata[Uart]),

.uart_rx_i,
.uart_irq_o (uart_irq),
.uart_tx_o
.clk_i(clk_sys_i), // clock
.rst_ni(rst_sys_ni), // reset not
.we(device_we[Uart]), // write enable
.be(device_be[Uart]), // byte enable
.uart_wdata_i(device_wdata[Uart]), // data bus
.addr_i(device_addr[Uart]), // addr bus
.uart_req_i(device_req[Uart]), // request from core (IBEX LSU)
.uart_rx_i(uart_rx_i), // rx line
.uart_tx_o(uart_tx_o), // tx line
.uart_rdata_o(device_rdata[Uart]), // data bus
.uart_req_gnt_o(), // request granted to core (IBEX LSU)
.uart_rvalid_o(device_rvalid[Uart]), // request valid to core (IBEX LSU)
.uart_irq_o(uart_irq), // interrupt request (CSR)
.uart_err_o() // error to core (IBEX LSU)
);

spi_top #(
Expand Down
63 changes: 63 additions & 0 deletions rtl/system/sync_fifo.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
module sync_fifo #(
parameter WIDTH = 32,
parameter DEPTH = 128
) (
input wire clk_i,
input wire rst_ni,
input wire [WIDTH-1:0] wdata_i,
input wire we_i,
input wire re_i,
output wire [WIDTH-1:0] rdata_o,
output wire full_o,
output wire empty_o,
output wire near_full_o,
output wire near_empty_o
);

localparam ADDR_BITS = $clog2(DEPTH); // address width for buffer

reg [ADDR_BITS:0] w_ptr, r_ptr;
wire [ADDR_BITS:0] w_ptr_incr, r_ptr_incr;
wire [ADDR_BITS:0] w_ptr_next, r_ptr_next;

wire [ADDR_BITS-1:0] w_addr, r_addr;

wire full_next, empty_next;

reg [WIDTH-1:0] mem [0:DEPTH-1];

assign w_ptr_incr = w_ptr + 1'b1;
assign r_ptr_incr = r_ptr + 1'b1;

assign w_ptr_next = (~full_o & we_i)? w_ptr_incr : w_ptr;
assign r_ptr_next = (~empty_o & re_i)? r_ptr_incr : r_ptr;

assign full_o = r_ptr == {~w_ptr[ADDR_BITS], w_ptr[ADDR_BITS-1:0]};
assign empty_o = r_ptr == w_ptr;

assign near_full_o = r_ptr == {~w_ptr_incr[ADDR_BITS], w_ptr_incr[ADDR_BITS-1:0]+1'b1};
assign near_empty_o = r_ptr_incr == w_ptr;

assign rdata_o = (empty_o)? {WIDTH{1'b0}} : mem[r_addr];

assign w_addr = w_ptr[ADDR_BITS-1:0];
assign r_addr = r_ptr[ADDR_BITS-1:0];

always @(posedge clk_i, negedge rst_ni) begin
if(~rst_ni) begin
w_ptr <= {ADDR_BITS+1{1'b0}};
r_ptr <= {ADDR_BITS+1{1'b0}};
end
else begin
w_ptr <= w_ptr_next;
r_ptr <= r_ptr_next;
end
end

always @(posedge clk_i) begin
if(we_i & ~full_o) begin
mem[w_addr] <= wdata_i;
end
end

endmodule
25 changes: 25 additions & 0 deletions rtl/system/synchronizer.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* 2 DFF sync clock domain crossing
* for async fifo queue
*/
`timescale 1ns/1ps
module sync_reg #(
parameter WIDTH = 32
) (
input wire clk_i,
input wire rst_ni,
input wire [WIDTH-1:0] wdata_i,
output reg [WIDTH-1:0] rdata_o
);

reg [WIDTH-1:0] p0;

always @(posedge clk_i, negedge rst_ni)
if(~rst_ni) begin
p0 <= 0;
rdata_o <= 0;
end
else
{rdata_o, p0} <= {p0, wdata_i};

endmodule
Loading