Loading files
#
# This file is part of LiteX.
#
# Copyright (c) 2015-2020 Florent Kermarrec <florent@enjoy-digital.fr>
# SPDX-License-Identifier: BSD-2-Clause
import serial
import struct
from litex.tools.remote.csr_builder import CSRBuilder
# Constants ----------------------------------------------------------------------------------------
CMD_WRITE_BURST_INCR = 0x01
CMD_READ_BURST_INCR = 0x02
CMD_WRITE_BURST_FIXED = 0x03
CMD_READ_BURST_FIXED = 0x04
UARTBONE_MAX_BURST_LENGTH = 255
UARTBONE_WRITE_TIMEOUT = 0.100
UARTBONE_WRITE_TIMEOUT_MARGIN = 0.5
# CommUART -----------------------------------------------------------------------------------------
class CommUART(CSRBuilder):
def __init__(self, port, baudrate=115200, csr_csv=None, debug=False, addr_width=32):
CSRBuilder.__init__(self, comm=self, csr_csv=csr_csv)
self.baudrate = int(float(baudrate))
self.debug = debug
self.addr_bytes = addr_width // 8
self.max_write_burst_length = self._get_max_write_burst_length(
baudrate = self.baudrate,
addr_bytes = self.addr_bytes,
)
self.port = serial.serial_for_url(port, self.baudrate)
@staticmethod
def _get_max_write_burst_length(baudrate, addr_bytes):
if baudrate <= 0:
raise ValueError("baudrate must be greater than 0.")
# UARTBone's gateware timeout is 100ms while outside RECEIVE-CMD.
# Keep half of that budget for serial transmission and leave the rest
# for Wishbone accesses and host/USB adapter jitter.
timeout = UARTBONE_WRITE_TIMEOUT*UARTBONE_WRITE_TIMEOUT_MARGIN
bytes_time = 10/baudrate # 1 start bit + 8 data bits + 1 stop bit.
max_bytes = int(timeout/bytes_time)
max_words = (max_bytes - (2 + addr_bytes)) // 4
return max(1, min(UARTBONE_MAX_BURST_LENGTH, max_words))
def open(self):
if hasattr(self, "port"):
return
self.port.open()
def close(self):
if not hasattr(self, "port"):
return
self.port.close()
del self.port
def _read(self, length):
r = bytes()
while len(r) < length:
r += self.port.read(length - len(r))
return r
def _write(self, data):
remaining = len(data)
pos = 0
while remaining:
written = self.port.write(data[pos:])
remaining -= written
pos += written
def _flush(self):
if self.port.inWaiting() > 0:
self.port.read(self.port.inWaiting())
def read(self, addr, length=None, burst="incr"):
self._flush()
data = []
length_int = 1 if length is None else length
cmd = {
"incr" : CMD_READ_BURST_INCR,
"fixed": CMD_READ_BURST_FIXED,
}[burst]
self._write([cmd, length_int])
self._write(list((addr//4).to_bytes(self.addr_bytes, byteorder="big")))
raw = self._read(4*length_int)
for i in range(length_int):
value = int.from_bytes(raw[4*i:4*(i + 1)], "big")
if self.debug:
print("read 0x{:08x} @ 0x{:08x}".format(value, addr + 4*i))
if length is None:
return value
data.append(value)
return data
def write(self, addr, data, burst="incr"):
self._flush()
data = data if isinstance(data, list) else [data]
length = len(data)
offset = 0
incr = burst == "incr"
cmd = {
"incr" : CMD_WRITE_BURST_INCR,
"fixed": CMD_WRITE_BURST_FIXED,
}[burst]
while length:
size = min(length, self.max_write_burst_length)
burst_addr = addr//4 + incr*offset
self._write([cmd, size])
self._write(list((burst_addr).to_bytes(self.addr_bytes, byteorder="big")))
payload = bytearray()
for i, value in enumerate(data[offset:offset+size]):
payload += value.to_bytes(4, byteorder="big")
if self.debug:
debug_addr = addr + 4*(offset + i) if incr else addr
print("write 0x{:08x} @ 0x{:08x}".format(value, debug_addr))
self._write(payload)
offset += size
length -= size
d368afb60This file is pinned to the selected release. Download the original to open it in your design tool.