Skip to content

Commit

Permalink
Merge pull request #7 from TUM-LIS/uart
Browse files Browse the repository at this point in the history
UART: Robust end-to-end flow control and logic reset
  • Loading branch information
wallento committed Jan 11, 2016
2 parents 5f49232 + b5c4952 commit 620330c
Show file tree
Hide file tree
Showing 13 changed files with 1,763 additions and 186 deletions.
2 changes: 1 addition & 1 deletion src/backend_uart/doc/logic.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,4 @@ The following resource utilization of the hardware logic was measured
on a Xilinx 7 Series device:

| LUTs | Registers | BRAMs |
| 180 | 185 | 1 |
| 323 | 154 | 2 |
12 changes: 9 additions & 3 deletions src/backend_uart/doc/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ Supported Features
==================
- Number of channels: 1 (fixed)
- FIFO width: 8 bit (fixed)

- Logic reset
- Robust end-to-end flow control, even without CTS/RTS

Components
==========
Expand All @@ -24,7 +25,7 @@ For details and usage instructions for the individual components, see these
pages:
- @ref backend_uart-sw "libglip Backend"
- @ref backend_uart-logic "FPGA Logic"

- @ref backend_uart-protocol "Details of the end-to-end flow control"

Performance
==========
Expand All @@ -33,4 +34,9 @@ As UART is a relatively slow interface, the backend usually reaches
the maximum throughput. That is 10 symbols (8 bit payload plus start
and stop bit), meaning BAUD/10 symbols Byte/s. For example, With
115,200 Baud you get 11,520 Byte/s and with 3,000,000 Baud you get
300,000 Byte/s.
300,000 Byte/s. There is a small loss of this theoretical throughput
as we need some flow control messages and mask the byte `0xfe` in the
data stream. With uniformly distributed random data you get
approximately 298,500 Byte/s at 3 MBaud. Hence you generally get
nearly full throughput, with the exception that it drops to roughly
50% if you only send the byte `0xfe`.
84 changes: 84 additions & 0 deletions src/backend_uart/doc/protocol.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
@defgroup backend_uart-protocol UART Protocol
@ingroup backend_uart

Standard UART does not have any out-of-band signaling, meaning we
cannot use control signals. The glip interface requires a reset signal
to reset the logic without board interaction. This signal needs to be
controlled by in-band signaling.

In-Band Signaling
-----------------

UART is one byte per transfer and we obviously want to use the full
byte in the default case. Hence one word is defined as a special
word. When this word needs to be transmitted, it needs to be
transferred twice. If the second word is not the same, that is a
control message. We use `0xfe` as `0x00` and `0xff` along with lower
numbers are safely assumed to be in the stream at a higher rate.

Example user data stream:

0xaf 0xfe 0x00 0xff

UART data stream:

0xaf 0xfe 0xfe 0x00 0xff

Credit-based Flow Control
-------------------------

The reset can happen at anytime, and especially when the input FIFO is
full as the user logic has deadlocked or similar. The problem now is
how to transfer a control word into the device when the input is
blocked. Hence, we need credit-based flow control, where the host gets
clearance from the device to send a certain amount of data. With each
transfer the host loses one of the credits and it needs to wait for
new credit from the device. This credit also needs to be transfered
in-band, meaning that we apply the same in-band signaling scheme
described above.

One may think it is safe to not implement flow control in the other
direction (logic->host), but to have a robust it is also required to
implement credit-based flow control there. In glip we don't make any
assumptions about when data is read and how input and output data
relate. Hence the back-pressure from the input may block the credit
messages and a deadlock in the user code may occur.

Summarizing, we need credit-based flow control in both directions.

Protocol Datagrams
------------------

From logic to host we have the following protocol datagrams:

| word 0 | word 1 | Description |
|--------------------|---------------|---------------|
| `{credit[14:8],1}` | `credit[7:0]` | Credit update |

From host to logic we have the following protocol datagrams:

| word 0 | word 1 | Description |
|----------------------|---------------|--------------------------|
| `{0,credit[13:8],1}` | `credit[7:0]` | Credit update |
| `100000r1` | - | Set logic rst pin to `r` |
| `100001r1` | - | Set comm rst pin to `r` |

The credit datagrams are exchanged as follows:

For the *ingress* path (host to logic), the credit is sent right after
reset of the communication. This reset is usually a board reset, but
most importantly when connecting from the host. The communication
controller then observes the data stream and updates the credit each
time it falls below the 50% threshold. This gives the host sufficient
time to actually receive this message before running out of credits,
and on the other hand does not imply too many messages.

For the *egress* path (logic to host), the host gives all initial
credit in a few tranches to the FPGA. It then also observes the
incoming data and sends a new credit of the maximum number that can be
transferred in one datagram (`0x3fff`) once the remaining credit falls
below the threshold of `HOST_BUFFER_SIZE - 0x3fff`.

The rst pin is set on demand by the user application. The
communications reset pin is used by the communication controller to
reset itself to a defined state.
8 changes: 6 additions & 2 deletions src/backend_uart/logic/demo/nexys4ddr/nexys4ddr.v
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,8 @@ module nexys4ddr
end
end

wire logic_rst;

glip_uart_toplevel
#(.FREQ(FREQ),
.BAUD(BAUD))
Expand All @@ -115,6 +117,8 @@ module nexys4ddr
.uart_cts (uart_cts),
.uart_rts (uart_rts),
.error (error),
.logic_rst (logic_rst),
.com_rst (com_rst),
.fifo_in_data (in_data),
.fifo_in_valid (in_valid),
.fifo_in_ready (in_ready),
Expand All @@ -128,15 +132,15 @@ module nexys4ddr
glip_measure_sevensegment
#(.FREQ(FREQ), .DIGITS(8), .OFFSET(0), .STEP(4'd1))
u_measure(.clk (clk),
.rst (rst),
.rst (logic_rst),
.trigger ((in_valid & in_ready) | (out_valid & out_ready)),
.digits (digits),
.overflow (overflow));

nexys4ddr_display
#(.FREQ(FREQ))
u_display(.clk (clk),
.rst (rst),
.rst (logic_rst),
.digits (digits),
.decpoints (8'b00001000),
.CA (CA),
Expand Down
5 changes: 5 additions & 0 deletions src/backend_uart/logic/demo/nexys4ddr/vivado.tcl
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,13 @@ set files [list \
"[file normalize "$origin_dir/nexys4ddr.v"]"\
"[file normalize "$origin_dir/../../../../common/logic/nexys4ddr/nexys4ddr_display.v"]"\
"[file normalize "$origin_dir/../../verilog/glip_uart_toplevel.v"]"\
"[file normalize "$origin_dir/../../verilog/glip_uart_control.v"]"\
"[file normalize "$origin_dir/../../verilog/glip_uart_control_egress.v"]"\
"[file normalize "$origin_dir/../../verilog/glip_uart_control_ingress.v"]"\
"[file normalize "$origin_dir/../../verilog/glip_uart_receive.v"]"\
"[file normalize "$origin_dir/../../verilog/glip_uart_transmit.v"]"\
"[file normalize "$origin_dir/../../../../common/logic/credit/verilog/creditor.v"]"\
"[file normalize "$origin_dir/../../../../common/logic/credit/verilog/debtor.v"]"\
"[file normalize "$origin_dir/../../../../common/logic/bcdcounter/bcdcounter.v"]"\
"[file normalize "$origin_dir/../../../../common/logic/sevensegment/sevensegment.v"]"\
"[file normalize "$origin_dir/../../../../common/logic/measure/glip_measure_sevensegment.v"]"\
Expand Down
Loading

3 comments on commit 620330c

@imphil
Copy link
Member

@imphil imphil commented on 620330c Jan 11, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR + immediate merge makes reviewing a bit hard, but here we go.

(most of it inline)

  • Please no tabs, spaces only.
  • We don't use //-style comments, only c89 style
  • I still don't really get the protocol description from protocol.md. Splitting the description into wire protocol and flow control, as discussed, might help.

@wallento
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PRs are documenting large code base changes instead of pushing directly to master. That way we can review the code and push patches or create issues. Will do this for your comments the next days.

@imphil
Copy link
Member

@imphil imphil commented on 620330c Jan 11, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd actually have preferred the feature development in a separate branch, and a merge to master after we've settled on a stable version, instead of a multitude of fixes in master, which make backouts, etc. rather hard. Please, let's do that the next time.

Please sign in to comment.