diff --git a/litex/tools/remote/etherbone.py b/litex/tools/remote/etherbone.py index cd955b4c0..fc24ad917 100644 --- a/litex/tools/remote/etherbone.py +++ b/litex/tools/remote/etherbone.py @@ -1,7 +1,7 @@ # # This file is part of LiteX. # -# Copyright (c) 2015-2019 Florent Kermarrec +# Copyright (c) 2015-2020 Florent Kermarrec # Copyright (c) 2017 Tim Ansell # SPDX-License-Identifier: BSD-2-Clause @@ -10,45 +10,47 @@ import struct from litex.soc.interconnect.packet import HeaderField, Header +# Etherbone Constants / Headers / Helpers ---------------------------------------------------------- -etherbone_magic = 0x4e6f -etherbone_version = 1 +etherbone_magic = 0x4e6f +etherbone_version = 1 etherbone_packet_header_length = 8 etherbone_packet_header_fields = { - "magic": HeaderField(0, 0, 16), + "magic": HeaderField(0, 0, 16), - "version": HeaderField(2, 4, 4), - "nr": HeaderField(2, 2, 1), # No Reads - "pr": HeaderField(2, 1, 1), # Probe Reply - "pf": HeaderField(2, 0, 1), # Probe Flag + "version": HeaderField(2, 4, 4), + "nr": HeaderField(2, 2, 1), # No Reads + "pr": HeaderField(2, 1, 1), # Probe Reply + "pf": HeaderField(2, 0, 1), # Probe Flag - "addr_size": HeaderField(3, 4, 4), # 1=8bits, 2=16bits, 4=32bits, 8=64bits - "port_size": HeaderField(3, 0, 4), # Same as above + "addr_size": HeaderField(3, 4, 4), # 1=8bits, 2=16bits, 4=32bits, 8=64bits + "port_size": HeaderField(3, 0, 4), # Same as above } -etherbone_packet_header = Header(etherbone_packet_header_fields, - etherbone_packet_header_length, - swap_field_bytes=True) +etherbone_packet_header = Header( + fields = etherbone_packet_header_fields, + length = etherbone_packet_header_length, + swap_field_bytes = True) + -# When reading/writing to a FIFO, you don't increase -# the address after each write. etherbone_record_header_length = 4 etherbone_record_header_fields = { - "bca": HeaderField(0, 0, 1), # ReplyToCfgSpace - ??? (C)onfig (A)dress - "rca": HeaderField(0, 1, 1), # ReadFromCfgSpace - (R)ead from (C)onfig (A)dress - "rff": HeaderField(0, 2, 1), # ReadFIFO - (R)ead (F)I(F)O - "cyc": HeaderField(0, 4, 1), # DropCycle - Drop(Cyc)le - "wca": HeaderField(0, 5, 1), # WriteToCfgSpace - (W)rite to (C)onfig (A)dress - "wff": HeaderField(0, 6, 1), # WriteFIFO - (W)rite (F)I(F)O + "bca": HeaderField(0, 0, 1), # ReplyToCfgSpace - ??? (C)onfig (A)dress + "rca": HeaderField(0, 1, 1), # ReadFromCfgSpace - (R)ead from (C)onfig (A)dress + "rff": HeaderField(0, 2, 1), # ReadFIFO - (R)ead (F)I(F)O + "cyc": HeaderField(0, 4, 1), # DropCycle - Drop(Cyc)le + "wca": HeaderField(0, 5, 1), # WriteToCfgSpace - (W)rite to (C)onfig (A)dress + "wff": HeaderField(0, 6, 1), # WriteFIFO - (W)rite (F)I(F)O - "byte_enable": HeaderField(1, 0, 8), # Select + "byte_enable": HeaderField(1, 0, 8), # Select - "wcount": HeaderField(2, 0, 8), # Writes + "wcount": HeaderField(2, 0, 8), # Writes - "rcount": HeaderField(3, 0, 8), # Reads + "rcount": HeaderField(3, 0, 8), # Reads } -etherbone_record_header = Header(etherbone_record_header_fields, - etherbone_record_header_length, - swap_field_bytes=True) +etherbone_record_header = Header( + fields = etherbone_record_header_fields, + length = etherbone_record_header_length, + swap_field_bytes = True) def split_bytes(v, n, endianness="big"): @@ -64,14 +66,16 @@ def get_field_data(field, datas): v = merge_bytes(datas[field.byte:field.byte+math.ceil(field.width/8)]) return (v >> field.offset) & (2**field.width-1) +# Packet ------------------------------------------------------------------------------------------- class Packet(list): def __init__(self, init=[]): self.ongoing = False - self.done = False + self.done = False for data in init: self.append(data) +# Etherbone Write / Read --------------------------------------------------------------------------- class EtherboneWrite: def __init__(self, data): @@ -88,13 +92,16 @@ class EtherboneRead: def __repr__(self): return "RD32 @ 0x{:08x}".format(self.addr) +# Etherbone Writes --------------------------------------------------------------------------------- class EtherboneWrites(Packet): def __init__(self, init=[], base_addr=0, datas=[]): + if isinstance(datas, list) and len(datas) > 255: + raise ValueError(f"Burst size of {len(datas)} exceeds maximum of 255 allowed by Etherbone.") Packet.__init__(self, init) self.base_addr = base_addr - self.writes = [] - self.encoded = init != [] + self.writes = [] + self.encoded = init != [] for data in datas: self.add(EtherboneWrite(data)) @@ -124,7 +131,7 @@ class EtherboneWrites(Packet): for i in range(4): base_addr.append(self.pop(0)) self.base_addr = merge_bytes(base_addr) - self.writes = [] + self.writes = [] while len(self) != 0: write = [] for i in range(4): @@ -140,13 +147,16 @@ class EtherboneWrites(Packet): r += write.__repr__() + "\n" return r +# Etherbone Reads ---------------------------------------------------------------------------------- class EtherboneReads(Packet): def __init__(self, init=[], base_ret_addr=0, addrs=[]): + if isinstance(addrs, list) and len(addrs) > 255: + raise ValueError(f"Burst size of {len(addrs)} exceeds maximum of 255 allowed by Etherbone.") Packet.__init__(self, init) self.base_ret_addr = base_ret_addr - self.reads = [] - self.encoded = init != [] + self.reads = [] + self.encoded = init != [] for addr in addrs: self.add(EtherboneRead(addr)) @@ -176,7 +186,7 @@ class EtherboneReads(Packet): for i in range(4): base_ret_addr.append(self.pop(0)) self.base_ret_addr = merge_bytes(base_ret_addr) - self.reads = [] + self.reads = [] while len(self) != 0: read = [] for i in range(4): @@ -192,22 +202,23 @@ class EtherboneReads(Packet): r += read.__repr__() + "\n" return r +# Etherbone Record --------------------------------------------------------------------------------- class EtherboneRecord(Packet): def __init__(self, init=[]): Packet.__init__(self, init) - self.writes = None - self.reads = None - self.bca = 0 - self.rca = 0 - self.rff = 0 - self.cyc = 0 - self.wca = 0 - self.wff = 0 + self.writes = None + self.reads = None + self.bca = 0 + self.rca = 0 + self.rff = 0 + self.cyc = 0 + self.wca = 0 + self.wff = 0 self.byte_enable = 0xf - self.wcount = 0 - self.rcount = 0 - self.encoded = init != [] + self.wcount = 0 + self.rcount = 0 + self.encoded = init != [] def get_writes(self): @@ -288,6 +299,7 @@ class EtherboneRecord(Packet): r += self.reads.__repr__() return r +# Etherbone Packet --------------------------------------------------------------------------------- class EtherbonePacket(Packet): def __init__(self, init=[]): @@ -295,17 +307,17 @@ class EtherbonePacket(Packet): self.encoded = init != [] self.records = [] - self.magic = etherbone_magic - self.version = etherbone_version + self.magic = etherbone_magic + self.version = etherbone_version self.addr_size = 32//8 self.port_size = 32//8 - self.nr = 0 - self.pr = 0 - self.pf = 0 + self.nr = 0 + self.pr = 0 + self.pf = 0 def get_records(self): records = [] - done = False + done = False payload = self while len(payload) != 0: record = EtherboneRecord(payload) @@ -356,6 +368,7 @@ class EtherbonePacket(Packet): r += record.__repr__(i) return r +# Etherbone IPC ------------------------------------------------------------------------------------ class EtherboneIPC: def send_packet(self, socket, packet): @@ -363,7 +376,7 @@ class EtherboneIPC: def receive_packet(self, socket): header_length = etherbone_packet_header_length + etherbone_record_header_length - packet = bytes() + packet = bytes() while len(packet) < header_length: chunk = socket.recv(header_length - len(packet)) if len(chunk) == 0: