From 5728f61f3a5ca7e0bc6af250c096d24659e3f12a Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Tue, 10 Feb 2015 21:29:14 +0100 Subject: [PATCH] etherbone: add model skeleton --- liteeth/common.py | 34 ++-- liteeth/test/Makefile | 1 + liteeth/test/model/etherbone.py | 283 ++++++++++++++++++++++++++++++++ liteeth/test/model/udp.py | 9 +- 4 files changed, 313 insertions(+), 14 deletions(-) create mode 100644 liteeth/test/model/etherbone.py diff --git a/liteeth/common.py b/liteeth/common.py index 6ac03099..0d57b912 100644 --- a/liteeth/common.py +++ b/liteeth/common.py @@ -90,23 +90,31 @@ etherbone_version = 1 etherbone_header_len = 8 etherbone_header = { "magic": HField( 0, 0, 16), - "portsize": HField( 2, 0, 4), - "addrsize": HField( 2, 4, 4), - "pf": HField( 3, 0, 1), - "version": HField( 4, 0, 4), - "wff": HField( 5, 1, 1), - "wca": HField( 5, 2, 1), - "cyc": HField( 5, 3, 1), - "rff": HField( 5, 5, 1), - "rca": HField( 5, 6, 1), - "bca": HField( 5, 7, 1), + "version": HField( 2, 4, 4), + "nr": HField( 2, 2, 1), + "pr": HField( 2, 1, 1), + "pf": HField( 2, 0, 1), - "rcount": HField( 6, 0, 8), - - "wcount": HField( 7, 0, 8) + "addr_size": HField( 3, 4, 4), + "port_size": HField( 3, 0, 4) } +etherbone_record_header_len = 4 +etherbone_record_header = { + "bca": HField( 0, 0, 1), + "rca": HField( 0, 1, 1), + "rff": HField( 0, 2, 1), + "cyc": HField( 0, 4, 1), + "wca": HField( 0, 5, 1), + "wff": HField( 0, 6, 1), + + "byte_enable": HField( 1, 0, 8), + + "wcount": HField( 2, 0, 8), + + "rcount": HField( 3, 0, 8) +} def reverse_bytes(v): n = math.ceil(flen(v)/8) diff --git a/liteeth/test/Makefile b/liteeth/test/Makefile index 43dd6771..fb6fcb58 100644 --- a/liteeth/test/Makefile +++ b/liteeth/test/Makefile @@ -9,6 +9,7 @@ model_tb: $(CMD) ./model/ip.py $(CMD) ./model/udp.py $(CMD) ./model/icmp.py + $(CMD) ./model/etherbone.py mac_core_tb: $(CMD) mac_core_tb.py diff --git a/liteeth/test/model/etherbone.py b/liteeth/test/model/etherbone.py new file mode 100644 index 00000000..430965d8 --- /dev/null +++ b/liteeth/test/model/etherbone.py @@ -0,0 +1,283 @@ +import math, copy + +from liteeth.common import * +from liteeth.test.common import * + +from liteeth.test.model import udp + +def print_etherbone(s): + print_with_prefix(s, "[ETHERBONE]") + +# Etherbone model +class EtherboneWrite: + def __init__(self, data): + self.data = data + + def __repr__(self): + return "Write data : {}".format(self.data) + + +class EtherboneRead: + def __init__(self, addr): + self.addr = addr + + def __repr__(self): + return "Read addr : {}".format(self.addr) + +class EtherboneWrites(Packet): + def __init__(self, init=[], base_addr=0): + Packet.__init__(self, init) + self.base_addr = base_addr + self.writes = [] + + def add(self, write): + self.writes.append(write) + + def encode(self): + for byte in split_bytes(self.base_addr, 4): + self.append(byte) + for write in self.writes: + for byte in split_bytes(write.data, 4): + self.append(byte) + + def decode(self): + base_addr = [] + for i in range(4): + base_addr.append(self.pop(0)) + self.base_addr = merge_bytes(base_addr) + self.writes = [] + while len(self) != 0: + write = [] + for i in range(4): + write.append(self.pop(0)) + self.writes.append(EtherboneWrite(merge_bytes(write))) + +class EtherboneReads(Packet): + def __init__(self, init=[], base_ret_addr=0): + Packet.__init__(self, init) + self.base_ret_addr = base_ret_addr + self.reads = [] + + def add(self, read): + self.reads.append(read) + + def encode(self): + for byte in split_bytes(self.base_ret_addr, 4): + self.append(byte) + for read in self.reads: + for byte in split_bytes(read.addr, 4): + self.append(byte) + + def decode(self): + base_ret_addr = [] + for i in range(4): + base_ret_addr.append(self.pop(0)) + self.base_ret_addr = merge_bytes(base_ret_addr) + self.reads = [] + while len(self) != 0: + read = [] + for i in range(4): + read.append(self.pop(0)) + self.reads.append(EtherboneRead(merge_bytes(read))) + +class EtherboneRecord(Packet): + def __init__(self, init=[]): + Packet.__init__(self, init) + self.writes = None + self.reads = None + + def get_writes(self): + if self.wcount == 0: + return None + else: + writes = [] + for i in range((self.wcount+1)*4): + writes.append(self.pop(0)) + return EtherboneWrites(writes) + + def get_reads(self): + if self.rcount == 0: + return None + else: + reads = [] + for i in range((self.rcount+1)*4): + reads.append(self.pop(0)) + return EtherboneReads(reads) + + def decode(self): + header = [] + for byte in self[:etherbone_record_header_len]: + header.append(self.pop(0)) + for k, v in sorted(etherbone_record_header.items()): + setattr(self, k, get_field_data(v, header)) + + def set_writes(self, writes): + self.writes = writes + writes.encode() + for byte in writes: + self.append(byte) + self.wcount = len(writes)-4 + + def set_reads(self, reads): + self.reads = reads + reads.encode() + for byte in reads: + self.append(byte) + self.rcount = len(reads)-4 + + def encode(self): + header = 0 + for k, v in sorted(etherbone_record_header.items()): + value = merge_bytes(split_bytes(getattr(self, k), math.ceil(v.width/8)), "little") + header += (value << v.offset+(v.byte*8)) + for d in split_bytes(header, etherbone_record_header_len): + self.insert(0, d) + + def __repr__(self): + r = "--------\n" + for k in sorted(etherbone_record_header.keys()): + r += k + " : 0x%x" %getattr(self,k) + "\n" + r += "payload: " + for d in self: + r += "%02x" %d + return r + +class EtherbonePacket(Packet): + def __init__(self, init=[]): + Packet.__init__(self, init) + + def get_records(self): + records = [] + done = False + payload = self + while len(payload) != 0: + record = EtherboneRecord(payload) + record.decode() + records.append(copy.deepcopy(record)) + writes = record.get_writes() + reads = record.get_reads() + payload = record + return records + + def decode(self): + header = [] + for byte in self[:etherbone_header_len]: + header.append(self.pop(0)) + for k, v in sorted(etherbone_header.items()): + setattr(self, k, get_field_data(v, header)) + + def set_records(self, records): + self.records = records + for record in records: + for byte in record: + self.append(byte) + + def encode(self): + header = 0 + for k, v in sorted(etherbone_header.items()): + value = merge_bytes(split_bytes(getattr(self, k), math.ceil(v.width/8)), "little") + header += (value << v.offset+(v.byte*8)) + for d in split_bytes(header, etherbone_header_len): + self.insert(0, d) + + def __repr__(self): + r = "--------\n" + for k in sorted(etherbone_header.keys()): + r += k + " : 0x%x" %getattr(self,k) + "\n" + r += "payload: " + for d in self: + r += "%02x" %d + return r + +class Etherbone(Module): + def __init__(self, udp, debug=False): + self.udp = udp + self.debug = debug + self.tx_packets = [] + self.tx_packet = EtherbonePacket() + self.rx_packet = EtherbonePacket() + + self.udp.set_etherbone_callback(self.callback) + + def send(self, packet): + packet.encode() + if self.debug: + print_etherbone(">>>>>>>>") + print_etherbone(packet) + udp_packet = udp.UDPPacket(packet) + udp_packet.src_port = 0x1234 + udp_packet.dst_port = 0x5678 + udp_packet.length = len(packet) + udp_packet.checksum = 0 + self.udp.send(udp_packet) + + def callback(self, packet): + packet = Etherbone(packet) + packet.decode() + if self.debug: + print_etherbone("<<<<<<<<") + print_etherbone(packet) + self.process(packet) + + def process(self, packet): + pass + +if __name__ == "__main__": + # Writes/Reads + writes = EtherboneWrites(base_addr=0x1000) + for i in range(16): + writes.add(EtherboneWrite(i)) + reads = EtherboneReads(base_ret_addr=0x2000) + for i in range(16): + reads.add(EtherboneRead(i)) + + # Record + record = EtherboneRecord() + record.set_writes(writes) + record.set_reads(reads) + record.bca = 0 + record.rca = 0 + record.rff = 0 + record.cyc = 0 + record.wca = 0 + record.wff = 0 + record.byte_enable = 0 + record.wcount = 16 + record.rcount = 16 + record.encode() + + # Packet + packet = EtherbonePacket() + packet.set_records([record for i in range(8)]) + packet.magic = etherbone_magic + packet.version = etherbone_version + packet.nr = 0 + packet.pr = 0 + packet.pf = 0 + packet.addr_size = 32//8 + packet.port_size = 32//8 + #print(packet) + packet.encode() + + # Send packet over UDP to check against Wireshark dissector + import socket + sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + sock.sendto(bytes(packet), ("192.168.1.1", 60368)) + + packet = EtherbonePacket(packet) + packet.decode() + #print(packet) + + # Record + records = packet.get_records() + for record in records: + writes = record.get_writes() + writes.decode() + print(writes.base_addr) + for e in writes.writes: + print(e) + reads = record.get_reads() + reads.decode() + print(reads.base_ret_addr) + for e in reads.reads: + print(e) diff --git a/liteeth/test/model/udp.py b/liteeth/test/model/udp.py index f48dcb29..7179b9ff 100644 --- a/liteeth/test/model/udp.py +++ b/liteeth/test/model/udp.py @@ -47,8 +47,13 @@ class UDP(Module): self.tx_packet = UDPPacket() self.rx_packet = UDPPacket() + self.etherbone_callback = None + self.ip.set_udp_callback(self.callback) + def set_etherbone_callback(callback): + self.etherbone_callback = callback + def send(self, packet): packet.encode() if self.debug: @@ -80,7 +85,9 @@ class UDP(Module): self.process(packet) def process(self, packet): - pass + if packet.dst_port == 22000: + if self.etherbone_callback is not None: + self.etherbone_callback(packet) if __name__ == "__main__": from liteeth.test.model.dumps import * -- 2.30.2