-from litex.soc.tools.remote import RemoteClient
+from litex.tools.litex_client import RemoteClient
\ No newline at end of file
chmod -x $@
endif
ifeq ($(CPUENDIANNESS),little)
- $(PYTHON) -m litex.soc.tools.mkmscimg $@ --little
+ $(PYTHON) -m litex.soc.software.mkmscimg $@ --little
else
- $(PYTHON) -m litex.soc.tools.mkmscimg $@
+ $(PYTHON) -m litex.soc.software.mkmscimg $@
endif
bios.elf: $(BIOS_DIRECTORY)/linker.ld $(OBJECTS)
--- /dev/null
+#!/usr/bin/env python3
+
+import argparse
+import binascii
+
+
+def insert_crc(i_filename, fbi_mode=False, o_filename=None, little_endian=False):
+ endian = "little" if little_endian else "big"
+
+ if o_filename is None:
+ o_filename = i_filename
+
+ with open(i_filename, "rb") as f:
+ fdata = f.read()
+ fcrc = binascii.crc32(fdata).to_bytes(4, byteorder=endian)
+ flength = len(fdata).to_bytes(4, byteorder=endian)
+
+ with open(o_filename, "wb") as f:
+ if fbi_mode:
+ f.write(flength)
+ f.write(fcrc)
+ f.write(fdata)
+ else:
+ f.write(fdata)
+ f.write(fcrc)
+
+
+def main():
+ parser = argparse.ArgumentParser(description="CRC32 computation tool and MiSoC image file writer.")
+ parser.add_argument("input", help="input file")
+ parser.add_argument("-o", "--output", default=None, help="output file (if not specified, use input file)")
+ parser.add_argument("-f", "--fbi", default=False, action="store_true", help="build flash boot image (FBI) file")
+ parser.add_argument("-l", "--little", default=False, action="store_true", help="Use little endian to write the CRC32")
+ args = parser.parse_args()
+ insert_crc(args.input, args.fbi, args.output, args.little)
+
+
+if __name__ == "__main__":
+ main()
+++ /dev/null
-#!/usr/bin/env python3
-
-import argparse
-import binascii
-
-
-def insert_crc(i_filename, fbi_mode=False, o_filename=None, little_endian=False):
- endian = "little" if little_endian else "big"
-
- if o_filename is None:
- o_filename = i_filename
-
- with open(i_filename, "rb") as f:
- fdata = f.read()
- fcrc = binascii.crc32(fdata).to_bytes(4, byteorder=endian)
- flength = len(fdata).to_bytes(4, byteorder=endian)
-
- with open(o_filename, "wb") as f:
- if fbi_mode:
- f.write(flength)
- f.write(fcrc)
- f.write(fdata)
- else:
- f.write(fdata)
- f.write(fcrc)
-
-
-def main():
- parser = argparse.ArgumentParser(description="CRC32 computation tool and MiSoC image file writer.")
- parser.add_argument("input", help="input file")
- parser.add_argument("-o", "--output", default=None, help="output file (if not specified, use input file)")
- parser.add_argument("-f", "--fbi", default=False, action="store_true", help="build flash boot image (FBI) file")
- parser.add_argument("-l", "--little", default=False, action="store_true", help="Use little endian to write the CRC32")
- args = parser.parse_args()
- insert_crc(args.input, args.fbi, args.output, args.little)
-
-
-if __name__ == "__main__":
- main()
+++ /dev/null
-from litex.soc.tools.remote.comm_uart import CommUART
-from litex.soc.tools.remote.comm_udp import CommUDP
-from litex.soc.tools.remote.comm_pcie import CommPCIe
-from litex.soc.tools.remote.comm_usb import CommUSB
-from litex.soc.tools.remote.litex_client import RemoteClient
+++ /dev/null
-import mmap
-
-
-class CommPCIe:
- def __init__(self, bar, debug=False):
- self.bar = bar
- self.debug = debug
-
- def open(self):
- if hasattr(self, "sysfs"):
- return
- self.sysfs = open(self.bar, "r+b")
- self.sysfs.flush()
- self.mmap = mmap.mmap(self.sysfs.fileno(), 0)
-
- def close(self):
- if not hasattr(self, "sysfs"):
- return
- self.mmap.close()
- del self.mmap
- self.sysfs.close()
- del self.sysfs
-
- def read(self, addr, length=None):
- data = []
- length_int = 1 if length is None else length
- for i in range(length_int):
- self.mmap.seek(addr + 4*i)
- value = int.from_bytes(self.mmap.read(4), byteorder="little")
- if self.debug:
- print("read {:08x} @ {:08x}".format(value, addr + 4*i))
- if length is None:
- return value
- data.append(value)
- return data
-
- def write(self, addr, data):
- data = data if isinstance(data, list) else [data]
- length = len(data)
- for i, value in enumerate(data):
- self.mmap[addr + 4*i:addr + 4*(i + 1)] = value.to_bytes(4, byteorder="little")
- if self.debug:
- print("write {:08x} @ {:08x}".format(value, addr + 4*i))
+++ /dev/null
-import serial
-import struct
-
-
-class CommUART:
- msg_type = {
- "write": 0x01,
- "read": 0x02
- }
- def __init__(self, port, baudrate=115200, debug=False):
- self.port = port
- self.baudrate = str(baudrate)
- self.debug = debug
- self.port = serial.serial_for_url(port, baudrate)
-
- 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):
- self._flush()
- data = []
- length_int = 1 if length is None else length
- self._write([self.msg_type["read"], length_int])
- self._write(list((addr//4).to_bytes(4, byteorder="big")))
- for i in range(length_int):
- value = int.from_bytes(self._read(4), "big")
- if self.debug:
- print("read {:08x} @ {:08x}".format(value, addr + 4*i))
- if length is None:
- return value
- data.append(value)
- return data
-
- def write(self, addr, data):
- self._flush()
- data = data if isinstance(data, list) else [data]
- length = len(data)
- offset = 0
- while length:
- size = min(length, 8)
- self._write([self.msg_type["write"], size])
- self._write(list(((addr+offset)//4).to_bytes(4, byteorder="big")))
- for i, value in enumerate(data[offset:offset+size]):
- self._write(list(value.to_bytes(4, byteorder="big")))
- if self.debug:
- print("write {:08x} @ {:08x}".format(value, addr + offset, 4*i))
- offset += size
- length -= size
+++ /dev/null
-import socket
-
-from litex.soc.tools.remote.etherbone import EtherbonePacket, EtherboneRecord
-from litex.soc.tools.remote.etherbone import EtherboneReads, EtherboneWrites
-
-
-class CommUDP:
- def __init__(self, server="192.168.1.50", port=1234, debug=False):
- self.server = server
- self.port = port
- self.debug = debug
-
- def open(self):
- if hasattr(self, "tx_socket"):
- return
- self.tx_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
- self.rx_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
- self.rx_socket.bind(("", self.port))
-
- def close(self):
- if not hasattr(self, "tx_socket"):
- return
- self.tx_socket.close()
- del self.tx_socket
- self.rx_socket.close()
- del self.rx_socket
-
- def read(self, addr, length=None):
- length_int = 1 if length is None else length
- record = EtherboneRecord()
- record.reads = EtherboneReads(addrs=[addr+4*j for j in range(length_int)])
- record.rcount = len(record.reads)
-
- packet = EtherbonePacket()
- packet.records = [record]
- packet.encode()
- self.tx_socket.sendto(bytes(packet), (self.server, self.port))
-
- datas, dummy = self.rx_socket.recvfrom(8192)
- packet = EtherbonePacket(datas)
- packet.decode()
- datas = packet.records.pop().writes.get_datas()
- if self.debug:
- for i, value in enumerate(datas):
- print("read {:08x} @ {:08x}".format(value, addr + 4*i))
- return datas[0] if length is None else datas
-
- def write(self, addr, datas):
- datas = datas if isinstance(datas, list) else [datas]
- length = len(datas)
- record = EtherboneRecord()
- record.writes = EtherboneWrites(base_addr=addr, datas=iter(datas))
- record.wcount = len(record.writes)
-
- packet = EtherbonePacket()
- packet.records = [record]
- packet.encode()
- self.tx_socket.sendto(bytes(packet), (self.server, self.port))
-
- if self.debug:
- for i, value in enumerate(datas):
- print("write {:08x} @ {:08x}".format(value, addr + 4*i))
+++ /dev/null
-import usb.core
-import time
-
-# Wishbone USB Protocol Bridge
-# ============================
-#
-# This module implements a bridge to connect LiteX to the target system's
-# Wishbone bus via USB. It uses `vendor` packets to communicate, which are
-# normally reserved. Since we're the vendors of this USB protocol, we take
-# advantage of this packet type to implement the bridge.
-#
-# All traffic goes to/from USB EP0, which is guaranteed to exist regardless
-# of the user's device implementation. The 8th bit of the first SETUP DATA
-# transaction contains all the information we need to mark this as a
-# Wishbone packet.
-#
-# Packets going to EP0 always start with a SETUP packet, followed by an IN
-# or an OUT packet, followed by an OUT or an IN packet.
-#
-# The SETUP packet looks like this:
-#
-# +----+----+----------+----+----+
-# | C0 | 00 | ADDRESS | 04 | 00 | read packet
-# +----+----+----------+----+----+
-# 1 1 4 1 1
-#
-# +----+----+----------+----+----+
-# | 40 | 00 | ADDRESS | 04 | 00 | write packet
-# +----+----+----------+----+----+
-# 1 1 4 1 1
-#
-# If the transaction is a "read" transaction, the device responds with an OUT
-# packet with the data. If the transaction is a "write" transaction, the host
-# responds with an IN packet with the data.
-#
-# Much like other Wishbone bridges, there are two types of packets. The first
-# byte indicates what type of packet it is, and that it is a Wishbone Bridge
-# packet. This is the value "0x40" (VENDOR type packet destined for DEVICE)
-# with the "Data Phase Transfer" bit either set or cleared:
-# - Read: 0xc0
-# - Write: 0x40
-#
-# The next byte is bRequest, which in the current implementation is unused.
-# Set this value to 0.
-#
-# The next four bytes form the wValue and wIndex values of the SETUP token.
-# We reuse these two 16-bit values as a single 32-bit ADDRESS packet. Note that
-# USB is big endian.
-#
-# Finally, the last two bytes indicate the length of the transaction. Since
-# we only support 32-bit reads and writes, this is always 4. On big endian
-# USB, this has the value {04, 00}.
-
-class CommUSB:
- def __init__(self, vid=None, pid=None, max_retries=10, debug=False):
- self.vid = vid
- self.pid = pid
- self.debug = debug
- self.max_retries = max_retries
- self.MAX_RECURSION_COUNT = 5
-
- def open(self):
- if hasattr(self, "dev"):
- return
- for t in range(self.max_retries):
- args = {}
- if self.vid is not None:
- args['idVendor'] = self.vid
- if self.pid is not None:
- args['idProduct'] = self.pid
- self.dev = usb.core.find(**args)
- if self.dev is not None:
- if self.debug:
- print("device connected after {} tries".format(t+1))
- return True
- del self.dev
- time.sleep(0.2 * t)
- print("unable to find usb device after {} tries".format(self.max_retries))
- return False
-
-
- def close(self):
- if not hasattr(self, "dev"):
- return
- del self.dev
-
- def read(self, addr, length=None):
- data = []
- length_int = 1 if length is None else length
- for i in range(length_int):
- value = self.usb_read(addr)
- # Note that sometimes, the value ends up as None when the device
- # disconnects during a transaction. Paper over this fact by
- # replacing it with a sentinal.
- if value is None:
- value = 0xffffffff
- if self.debug:
- print("read {:08x} @ {:08x}".format(value, addr))
- if length is None:
- return value
- data.append(value)
- return data
-
- def usb_read(self, addr, depth=0):
- try:
- value = self.dev.ctrl_transfer(bmRequestType=0xc0,
- bRequest=0x00,
- wValue=addr & 0xffff,
- wIndex=(addr >> 16) & 0xffff,
- data_or_wLength=4)
- if value is None:
- raise TypeError
- return int.from_bytes(value, byteorder="little")
- except (usb.core.USBError, TypeError):
- self.close()
- self.open()
- if depth < self.MAX_RECURSION_COUNT:
- return self.usb_read(addr, depth+1)
-
- def write(self, addr, data):
- data = data if isinstance(data, list) else [data]
- length = len(data)
- for i, value in enumerate(data):
- self.usb_write(addr, value)
- if self.debug:
- print("write {:08x} @ {:08x}".format(value, addr + 4*i))
-
- def usb_write(self, addr, value, depth=0):
- try:
- self.dev.ctrl_transfer(bmRequestType=0x40, bRequest=0x00,
- wValue=addr & 0xffff,
- wIndex=(addr >> 16) & 0xffff,
- data_or_wLength=bytes([(value >> 0) & 0xff,
- (value >> 8) & 0xff,
- (value >> 16) & 0xff,
- (value >> 24) & 0xff]
- ), timeout=None)
- except usb.core.USBError:
- self.close()
- self.open()
- if depth < self.MAX_RECURSION_COUNT:
- return self.usb_write(addr, value, depth+1)
+++ /dev/null
-import csv
-
-
-class CSRElements:
- def __init__(self, d):
- self.__dict__.update(d)
-
- @property
- def d(self):
- return self.__dict__
-
- def __getattr__(self, attr):
- try:
- return self.__dict__[attr]
- except KeyError:
- pass
- raise AttributeError("No such element " + attr)
-
-
-class CSRRegister:
- def __init__(self, readfn, writefn, name, addr, length, data_width, mode):
- self.readfn = readfn
- self.writefn = writefn
- self.name = name
- self.addr = addr
- self.length = length
- self.data_width = data_width
- self.mode = mode
-
- def read(self):
- if self.mode not in ["rw", "ro"]:
- raise KeyError(self.name + "register not readable")
- datas = self.readfn(self.addr, length=self.length)
- if isinstance(datas, int):
- return datas
- else:
- data = 0
- for i in range(self.length):
- data = data << self.data_width
- data |= datas[i]
- return data
-
- def write(self, value):
- if self.mode not in ["rw", "wo"]:
- raise KeyError(self.name + "register not writable")
- datas = []
- for i in range(self.length):
- datas.append((value >> ((self.length-1-i)*self.data_width)) & (2**self.data_width-1))
- self.writefn(self.addr, datas)
-
-
-class CSRMemoryRegion:
- def __init__(self, base, size):
- self.base = base
- self.size = size
-
-
-class CSRBuilder:
- def __init__(self, comm, csr_csv, csr_data_width=None):
- self.constants = self.build_constants(csr_csv)
-
- # Load csr_data_width from the constants, otherwise it must be provided
- constant_csr_data_width = self.constants.d.get('csr_data_width', None)
- if csr_data_width is None:
- csr_data_width = constant_csr_data_width
- if csr_data_width is None:
- raise KeyError('csr_data_width not found in constants, please provide!')
- if csr_data_width != constant_csr_data_width:
- raise KeyError('csr_data_width of {} provided but {} found in constants'.format(
- csr_data_width, constant_csr_data_width))
-
- self.csr_data_width = csr_data_width
- self.bases = self.build_bases(csr_csv)
- self.regs = self.build_registers(csr_csv, comm.read, comm.write)
- self.mems = self.build_memories(csr_csv)
-
- def build_bases(self, csr_csv):
- csv_reader = csv.reader(open(csr_csv), delimiter=',', quotechar='#')
- d = {}
- for item in csv_reader:
- group, name, addr, dummy0, dummy1 = item
- if group == "csr_base":
- d[name] = int(addr.replace("0x", ""), 16)
- return CSRElements(d)
-
- def build_registers(self, csr_csv, readfn, writefn):
- csv_reader = csv.reader(open(csr_csv), delimiter=',', quotechar='#')
- d = {}
- for item in csv_reader:
- group, name, addr, length, mode = item
- if group == "csr_register":
- addr = int(addr.replace("0x", ""), 16)
- length = int(length)
- d[name] = CSRRegister(readfn, writefn, name, addr, length, self.csr_data_width, mode)
- return CSRElements(d)
-
- def build_constants(self, csr_csv):
- csv_reader = csv.reader(open(csr_csv), delimiter=',', quotechar='#')
- d = {}
- for item in csv_reader:
- group, name, value, dummy0, dummy1 = item
- if group == "constant":
- try:
- d[name] = int(value)
- except:
- d[name] = value
- return CSRElements(d)
-
- def build_memories(self, csr_csv):
- csv_reader = csv.reader(open(csr_csv), delimiter=',', quotechar='#')
- d = {}
- for item in csv_reader:
- group, name, base, size, dummy1 = item
- if group == "memory_region":
- d[name] = CSRMemoryRegion(int(base, 16), int(size))
- return CSRElements(d)
+++ /dev/null
-import math
-import struct
-
-from litex.soc.interconnect.stream_packet import HeaderField, Header
-
-
-etherbone_magic = 0x4e6f
-etherbone_version = 1
-etherbone_packet_header_length = 8
-etherbone_packet_header_fields = {
- "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
-
- "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)
-
-# 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
-
- "byte_enable": HeaderField(1, 0, 8), # Select
-
- "wcount": HeaderField(2, 0, 8), # Writes
-
- "rcount": HeaderField(3, 0, 8), # Reads
-}
-etherbone_record_header = Header(etherbone_record_header_fields,
- etherbone_record_header_length,
- swap_field_bytes=True)
-
-
-def split_bytes(v, n, endianness="big"):
- r = []
- return v.to_bytes(n, byteorder=endianness)
-
-
-def merge_bytes(b, endianness="big"):
- return int.from_bytes(b, endianness)
-
-
-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)
-
-
-class Packet(list):
- def __init__(self, init=[]):
- self.ongoing = False
- self.done = False
- for data in init:
- self.append(data)
-
-
-class EtherboneWrite:
- def __init__(self, data):
- self.data = data
-
- def __repr__(self):
- return "WR32 0x{:08x}".format(self.data)
-
-
-class EtherboneRead:
- def __init__(self, addr):
- self.addr = addr
-
- def __repr__(self):
- return "RD32 @ 0x{:08x}".format(self.addr)
-
-
-class EtherboneWrites(Packet):
- def __init__(self, init=[], base_addr=0, datas=[]):
- Packet.__init__(self, init)
- self.base_addr = base_addr
- self.writes = []
- self.encoded = init != []
- for data in datas:
- self.add(EtherboneWrite(data))
-
- def add(self, write):
- self.writes.append(write)
-
- def get_datas(self):
- datas = []
- for write in self.writes:
- datas.append(write.data)
- return datas
-
- def encode(self):
- if self.encoded:
- raise ValueError
- 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)
- self.encoded = True
-
- def decode(self):
- if not self.encoded:
- raise ValueError
- 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)))
- self.encoded = False
-
- def __repr__(self):
- r = "Writes\n"
- r += "--------\n"
- r += "BaseAddr @ 0x{:08x}\n".format(self.base_addr)
- for write in self.writes:
- r += write.__repr__() + "\n"
- return r
-
-
-class EtherboneReads(Packet):
- def __init__(self, init=[], base_ret_addr=0, addrs=[]):
- Packet.__init__(self, init)
- self.base_ret_addr = base_ret_addr
- self.reads = []
- self.encoded = init != []
- for addr in addrs:
- self.add(EtherboneRead(addr))
-
- def add(self, read):
- self.reads.append(read)
-
- def get_addrs(self):
- addrs = []
- for read in self.reads:
- addrs.append(read.addr)
- return addrs
-
- def encode(self):
- if self.encoded:
- raise ValueError
- 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)
- self.encoded = True
-
- def decode(self):
- if not self.encoded:
- raise ValueError
- 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)))
- self.encoded = False
-
- def __repr__(self):
- r = "Reads\n"
- r += "--------\n"
- r += "BaseRetAddr @ 0x{:08x}\n".format(self.base_ret_addr)
- for read in self.reads:
- r += read.__repr__() + "\n"
- return r
-
-
-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.byte_enable = 0xf
- self.wcount = 0
- self.rcount = 0
- self.encoded = init != []
-
-
- 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):
- if not self.encoded:
- raise ValueError
- header = []
- for byte in self[:etherbone_record_header.length]:
- header.append(self.pop(0))
- for k, v in sorted(etherbone_record_header.fields.items()):
- setattr(self, k, get_field_data(v, header))
- self.writes = self.get_writes()
- if self.writes is not None:
- self.writes.decode()
- self.reads = self.get_reads()
- if self.reads is not None:
- self.reads.decode()
- self.encoded = False
-
- def set_writes(self, writes):
- self.wcount = len(writes.writes)
- writes.encode()
- for byte in writes:
- self.append(byte)
-
- def set_reads(self, reads):
- self.rcount = len(reads.reads)
- reads.encode()
- for byte in reads:
- self.append(byte)
-
- def encode(self):
- if self.encoded:
- raise ValueError
- if self.writes is not None:
- self.set_writes(self.writes)
- if self.reads is not None:
- self.set_reads(self.reads)
- header = 0
- for k, v in sorted(etherbone_record_header.fields.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.length):
- self.insert(0, d)
- self.encoded = True
-
- def __repr__(self, n=0):
- r = "Record {}\n".format(n)
- r += "--------\n"
- if self.encoded:
- for d in self:
- r += "{:02x}".format(d)
- else:
- for k in sorted(etherbone_record_header.fields.keys()):
- r += k + " : 0x{:0x}\n".format(getattr(self, k))
- if self.wcount != 0:
- r += self.writes.__repr__()
- if self.rcount != 0:
- r += self.reads.__repr__()
- return r
-
-
-class EtherbonePacket(Packet):
- def __init__(self, init=[]):
- Packet.__init__(self, init)
- self.encoded = init != []
- self.records = []
-
- 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
-
- def get_records(self):
- records = []
- done = False
- payload = self
- while len(payload) != 0:
- record = EtherboneRecord(payload)
- record.decode()
- records.append(record)
- payload = record[:]
- return records
-
- def decode(self):
- if not self.encoded:
- raise ValueError
- header = []
- for byte in self[:etherbone_packet_header.length]:
- header.append(self.pop(0))
- for k, v in sorted(etherbone_packet_header.fields.items()):
- setattr(self, k, get_field_data(v, header))
- self.records = self.get_records()
- self.encoded = False
-
- def set_records(self, records):
- for record in records:
- record.encode()
- for byte in record:
- self.append(byte)
-
- def encode(self):
- if self.encoded:
- raise ValueError
- self.set_records(self.records)
- header = 0
- for k, v in sorted(etherbone_packet_header.fields.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_packet_header.length):
- self.insert(0, d)
- self.encoded = True
-
- def __repr__(self):
- r = "Packet\n"
- r += "--------\n"
- if self.encoded:
- for d in self:
- r += "{:02x}".format(d)
- else:
- for k in sorted(etherbone_packet_header.fields.keys()):
- r += k + " : 0x{:0x}\n".format(getattr(self, k))
- for i, record in enumerate(self.records):
- r += record.__repr__(i)
- return r
-
-
-class EtherboneIPC:
- def send_packet(self, socket, packet):
- socket.sendall(bytes(packet))
-
- def receive_packet(self, socket):
- header_length = etherbone_packet_header_length + etherbone_record_header_length
- packet = bytes()
- while len(packet) < header_length:
- chunk = socket.recv(header_length - len(packet))
- if len(chunk) == 0:
- return 0
- else:
- packet += chunk
- wcount, rcount = struct.unpack(">BB", packet[header_length-2:])
- counts = wcount + rcount
- packet_size = header_length + 4*(counts + 1)
- while len(packet) < packet_size:
- chunk = socket.recv(packet_size - len(packet))
- if len(chunk) == 0:
- return 0
- else:
- packet += chunk
- return packet
+++ /dev/null
-import socket
-
-from litex.soc.tools.remote.etherbone import EtherbonePacket, EtherboneRecord
-from litex.soc.tools.remote.etherbone import EtherboneReads, EtherboneWrites
-from litex.soc.tools.remote.etherbone import EtherboneIPC
-from litex.soc.tools.remote.csr_builder import CSRBuilder
-
-
-class RemoteClient(EtherboneIPC, CSRBuilder):
- def __init__(self, host="localhost", port=1234, csr_csv="csr.csv", csr_data_width=None, debug=False):
- if csr_csv is not None:
- CSRBuilder.__init__(self, self, csr_csv, csr_data_width)
- else:
- assert csr_data_width is not None
- self.host = host
- self.port = port
- self.debug = debug
-
- def open(self):
- if hasattr(self, "socket"):
- return
- self.socket = socket.create_connection((self.host, self.port), 5.0)
- self.socket.settimeout(5.0)
-
- def close(self):
- if not hasattr(self, "socket"):
- return
- self.socket.close()
- del self.socket
-
- def read(self, addr, length=None):
- length_int = 1 if length is None else length
- # prepare packet
- record = EtherboneRecord()
- record.reads = EtherboneReads(addrs=[addr + 4*j for j in range(length_int)])
- record.rcount = len(record.reads)
-
- # send packet
- packet = EtherbonePacket()
- packet.records = [record]
- packet.encode()
- self.send_packet(self.socket, packet[:])
-
- # receive response
- packet = EtherbonePacket(self.receive_packet(self.socket))
- packet.decode()
- datas = packet.records.pop().writes.get_datas()
- if self.debug:
- for i, data in enumerate(datas):
- print("read {:08x} @ {:08x}".format(data, addr + 4*i))
- return datas[0] if length is None else datas
-
- def write(self, addr, datas):
- datas = datas if isinstance(datas, list) else [datas]
- record = EtherboneRecord()
- record.writes = EtherboneWrites(base_addr=addr, datas=[d for d in datas])
- record.wcount = len(record.writes)
-
- packet = EtherbonePacket()
- packet.records = [record]
- packet.encode()
- self.send_packet(self.socket, packet)
-
- if self.debug:
- for i, data in enumerate(datas):
- print("write {:08x} @ {:08x}".format(data, addr + 4*i))
--- /dev/null
+import socket
+
+from litex.tools.remote.etherbone import EtherbonePacket, EtherboneRecord
+from litex.tools.remote.etherbone import EtherboneReads, EtherboneWrites
+from litex.tools.remote.etherbone import EtherboneIPC
+from litex.tools.remote.csr_builder import CSRBuilder
+
+
+class RemoteClient(EtherboneIPC, CSRBuilder):
+ def __init__(self, host="localhost", port=1234, csr_csv="csr.csv", csr_data_width=None, debug=False):
+ if csr_csv is not None:
+ CSRBuilder.__init__(self, self, csr_csv, csr_data_width)
+ else:
+ assert csr_data_width is not None
+ self.host = host
+ self.port = port
+ self.debug = debug
+
+ def open(self):
+ if hasattr(self, "socket"):
+ return
+ self.socket = socket.create_connection((self.host, self.port), 5.0)
+ self.socket.settimeout(5.0)
+
+ def close(self):
+ if not hasattr(self, "socket"):
+ return
+ self.socket.close()
+ del self.socket
+
+ def read(self, addr, length=None):
+ length_int = 1 if length is None else length
+ # prepare packet
+ record = EtherboneRecord()
+ record.reads = EtherboneReads(addrs=[addr + 4*j for j in range(length_int)])
+ record.rcount = len(record.reads)
+
+ # send packet
+ packet = EtherbonePacket()
+ packet.records = [record]
+ packet.encode()
+ self.send_packet(self.socket, packet[:])
+
+ # receive response
+ packet = EtherbonePacket(self.receive_packet(self.socket))
+ packet.decode()
+ datas = packet.records.pop().writes.get_datas()
+ if self.debug:
+ for i, data in enumerate(datas):
+ print("read {:08x} @ {:08x}".format(data, addr + 4*i))
+ return datas[0] if length is None else datas
+
+ def write(self, addr, datas):
+ datas = datas if isinstance(datas, list) else [datas]
+ record = EtherboneRecord()
+ record.writes = EtherboneWrites(base_addr=addr, datas=[d for d in datas])
+ record.wcount = len(record.writes)
+
+ packet = EtherbonePacket()
+ packet.records = [record]
+ packet.encode()
+ self.send_packet(self.socket, packet)
+
+ if self.debug:
+ for i, data in enumerate(datas):
+ print("write {:08x} @ {:08x}".format(data, addr + 4*i))
--- /dev/null
+#!/usr/bin/env python3
+import os
+import sys
+import json
+
+from litex.build import tools
+
+def main():
+ if len(sys.argv) < 2:
+ print("usage: litex_read_verilog verilog_file [module]")
+ exit(1)
+
+ verilog_file = sys.argv[1]
+ json_file = verilog_file + ".json"
+ module = None if len(sys.argv) < 3 else sys.argv[2]
+
+ # use yosys to convert verilog to json
+ yosys_v2j = "\n".join([
+ "read_verilog -sv {}".format(verilog_file),
+ "write_json {}.json".format(verilog_file)
+ ])
+ tools.write_to_file("yosys_v2j.ys", yosys_v2j)
+ os.system("yosys -q yosys_v2j.ys")
+
+ # load json and convert to migen module
+ f = open(json_file, "r")
+ j = json.load(f)
+
+ # create list of modules
+ modules = [module] if module is not None else j["modules"].keys()
+
+ # create migen definitions
+ for module in modules:
+ migen_def = []
+ migen_def.append("class {}(Module):".format(module))
+ migen_def.append(" "*4 + "def __init__(self):")
+ for name, info in j["modules"][module]["ports"].items():
+ length = "" if len(info["bits"]) == 1 else len(info["bits"])
+ migen_def.append(" " * 8 + "self.{} = Signal({})".format(name, length))
+ migen_def.append("")
+ migen_def.append(" "*8 + "# # #")
+ migen_def.append("")
+ migen_def.append(" "*8 + "self.specials += Instance(\"{}\",".format(module))
+ for name, info in j["modules"][module]["ports"].items():
+ io_prefix = {
+ "input": "i",
+ "output": "o",
+ "inout": "io"
+ }[info["direction"]]
+ migen_def.append(" "*12 + "{}_{}=self.{},".format(io_prefix, name, name))
+ migen_def.append(" "*8 + ")")
+ migen_def.append("")
+ print("\n".join(migen_def))
+
+ # keep things clean after us
+ os.system("rm " + json_file)
+
+
+if __name__ == "__main__":
+ main()
--- /dev/null
+#!/usr/bin/env python3
+
+import argparse
+
+import sys
+import socket
+import time
+import threading
+
+from litex.tools.remote.etherbone import EtherbonePacket, EtherboneRecord, EtherboneWrites
+from litex.tools.remote.etherbone import EtherboneIPC
+
+
+class RemoteServer(EtherboneIPC):
+ def __init__(self, comm, bind_ip, bind_port=1234):
+ self.comm = comm
+ self.bind_ip = bind_ip
+ self.bind_port = bind_port
+ self.lock = False
+
+ def open(self):
+ if hasattr(self, "socket"):
+ return
+ self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
+ self.socket.bind((self.bind_ip, self.bind_port))
+ print("tcp port: {:d}".format(self.bind_port))
+ self.socket.listen(1)
+ self.comm.open()
+
+ def close(self):
+ self.comm.close()
+ if not hasattr(self, "socket"):
+ return
+ self.socket.close()
+ del self.socket
+
+ def _serve_thread(self):
+ while True:
+ client_socket, addr = self.socket.accept()
+ print("Connected with " + addr[0] + ":" + str(addr[1]))
+ try:
+ while True:
+ try:
+ packet = self.receive_packet(client_socket)
+ if packet == 0:
+ break
+ except:
+ break
+ packet = EtherbonePacket(packet)
+ packet.decode()
+
+ record = packet.records.pop()
+
+ # wait for lock
+ while self.lock:
+ time.sleep(0.01)
+
+ # set lock
+ self.lock = True
+
+ # handle writes:
+ if record.writes != None:
+ self.comm.write(record.writes.base_addr, record.writes.get_datas())
+
+ # handle reads
+ if record.reads != None:
+ reads = []
+ for addr in record.reads.get_addrs():
+ reads.append(self.comm.read(addr))
+
+ record = EtherboneRecord()
+ record.writes = EtherboneWrites(datas=reads)
+ record.wcount = len(record.writes)
+
+ packet = EtherbonePacket()
+ packet.records = [record]
+ packet.encode()
+ self.send_packet(client_socket, packet)
+
+ # release lock
+ self.lock = False
+
+ finally:
+ print("Disconnect")
+ client_socket.close()
+
+ def start(self, nthreads):
+ for i in range(nthreads):
+ self.serve_thread = threading.Thread(target=self._serve_thread)
+ self.serve_thread.setDaemon(True)
+ self.serve_thread.start()
+
+
+def main():
+ print("LiteX remote server")
+ parser = argparse.ArgumentParser()
+ # Common arguments
+ parser.add_argument("--bind-ip", default="localhost",
+ help="Host bind address")
+ parser.add_argument("--bind-port", default=1234,
+ help="Host bind port")
+
+ # UART arguments
+ parser.add_argument("--uart", action="store_true",
+ help="Select UART interface")
+ parser.add_argument("--uart-port", default=None,
+ help="Set UART port")
+ parser.add_argument("--uart-baudrate", default=115200,
+ help="Set UART baudrate")
+
+ # UDP arguments
+ parser.add_argument("--udp", action="store_true",
+ help="Select UDP interface")
+ parser.add_argument("--udp-ip", default="192.168.1.50",
+ help="Set UDP remote IP address")
+ parser.add_argument("--udp-port", default=1234,
+ help="Set UDP remote port")
+
+ # PCIe arguments
+ parser.add_argument("--pcie", action="store_true",
+ help="Select PCIe interface")
+ parser.add_argument("--pcie-bar", default=None,
+ help="Set PCIe BAR")
+
+ # USB arguments
+ parser.add_argument("--usb", action="store_true",
+ help="Select USB interface")
+ parser.add_argument("--usb-vid", default=None,
+ help="Set USB vendor ID")
+ parser.add_argument("--usb-pid", default=None,
+ help="Set USB product ID")
+ parser.add_argument("--usb-max-retries", default=10,
+ help="Number of times to try reconnecting to USB")
+ args = parser.parse_args()
+
+
+ if args.uart:
+ from litex.tools.remote import CommUART
+ if args.uart_port is None:
+ print("Need to specify --uart-port, exiting.")
+ exit()
+ uart_port = args.uart_port
+ uart_baudrate = int(float(args.uart_baudrate))
+ print("[CommUART] port: {} / baudrate: {} / ".format(uart_port, uart_baudrate), end="")
+ comm = CommUART(uart_port, uart_baudrate)
+ elif args.udp:
+ from litex.tools.remote import CommUDP
+ udp_ip = args.udp_ip
+ udp_port = int(args.udp_port)
+ print("[CommUDP] ip: {} / port: {} / ".format(udp_ip, udp_port), end="")
+ comm = CommUDP(udp_ip, udp_port)
+ elif args.pcie:
+ from litex.tools.remote import CommPCIe
+ pcie_bar = args.pcie_bar
+ if args.pcie_bar is None:
+ print("Need to speficy --pcie-bar, exiting.")
+ exit()
+ print("[CommPCIe] bar: {} / ".format(args.pcie_bar), end="")
+ comm = CommPCIe(args.pcie_bar)
+ elif args.usb:
+ from litex.tools.remote import CommUSB
+ if args.usb_pid is None and args.usb_vid is None:
+ print("Need to speficy --usb-vid or --usb-pid, exiting.")
+ exit()
+ print("[CommUSB] vid: {} / pid: {} / ".format(args.usb_vid, args.usb_pid), end="")
+ pid = args.usb_pid
+ if pid is not None:
+ pid = int(pid, base=0)
+ vid = args.usb_vid
+ if vid is not None:
+ vid = int(vid, base=0)
+ comm = CommUSB(vid=vid, pid=pid, max_retries=args.usb_max_retries)
+ else:
+ parser.print_help()
+ exit()
+
+ server = RemoteServer(comm, args.bind_ip, int(args.bind_port))
+ server.open()
+ server.start(4)
+ try:
+ import time
+ while True: time.sleep(100)
+ except KeyboardInterrupt:
+ pass
+
+if __name__ == "__main__":
+ main()
--- /dev/null
+#!/usr/bin/env python3
+
+import argparse
+
+from migen import *
+from migen.genlib.io import CRG
+
+from litex.build.generic_platform import *
+from litex.build.sim import SimPlatform
+from litex.build.sim.config import SimConfig
+
+from litex.soc.integration.soc_core import *
+from litex.soc.integration.soc_sdram import *
+from litex.soc.integration.builder import *
+from litex.soc.cores import uart
+from litex.soc.integration.soc_core import mem_decoder
+
+from litedram.common import PhySettings
+from litedram.modules import MT48LC16M16
+from litedram.phy.model import SDRAMPHYModel
+
+from liteeth.common import convert_ip
+from liteeth.phy.model import LiteEthPHYModel
+from liteeth.core.mac import LiteEthMAC
+from liteeth.core import LiteEthUDPIPCore
+from liteeth.frontend.etherbone import LiteEthEtherbone
+
+from litescope import LiteScopeAnalyzer
+
+
+class SimPins(Pins):
+ def __init__(self, n=1):
+ Pins.__init__(self, "s "*n)
+
+
+_io = [
+ ("sys_clk", 0, SimPins(1)),
+ ("sys_rst", 0, SimPins(1)),
+ ("serial", 0,
+ Subsignal("source_valid", SimPins()),
+ Subsignal("source_ready", SimPins()),
+ Subsignal("source_data", SimPins(8)),
+
+ Subsignal("sink_valid", SimPins()),
+ Subsignal("sink_ready", SimPins()),
+ Subsignal("sink_data", SimPins(8)),
+ ),
+ ("eth_clocks", 0,
+ Subsignal("none", SimPins()),
+ ),
+ ("eth", 0,
+ Subsignal("source_valid", SimPins()),
+ Subsignal("source_ready", SimPins()),
+ Subsignal("source_data", SimPins(8)),
+
+ Subsignal("sink_valid", SimPins()),
+ Subsignal("sink_ready", SimPins()),
+ Subsignal("sink_data", SimPins(8)),
+ ),
+ ("eth_clocks", 1,
+ Subsignal("none", SimPins()),
+ ),
+ ("eth", 1,
+ Subsignal("source_valid", SimPins()),
+ Subsignal("source_ready", SimPins()),
+ Subsignal("source_data", SimPins(8)),
+
+ Subsignal("sink_valid", SimPins()),
+ Subsignal("sink_ready", SimPins()),
+ Subsignal("sink_data", SimPins(8)),
+ ),
+]
+
+
+class Platform(SimPlatform):
+ default_clk_name = "sys_clk"
+ default_clk_period = 1000 # ~ 1MHz
+
+ def __init__(self):
+ SimPlatform.__init__(self, "SIM", _io)
+
+ def do_finalize(self, fragment):
+ pass
+
+
+class SimSoC(SoCSDRAM):
+ csr_peripherals = [
+ "ethphy",
+ "ethmac",
+
+ "etherbonephy",
+ "etherbonecore",
+
+ "analyzer",
+ ]
+ csr_map_update(SoCSDRAM.csr_map, csr_peripherals)
+
+ interrupt_map = {
+ "ethmac": 3,
+ }
+ interrupt_map.update(SoCSDRAM.interrupt_map)
+
+ mem_map = {
+ "ethmac": 0x30000000, # (shadow @0xb0000000)
+ }
+ mem_map.update(SoCSDRAM.mem_map)
+
+ def __init__(self,
+ with_sdram=False,
+ with_ethernet=False,
+ with_etherbone=False, etherbone_mac_address=0x10e2d5000000, etherbone_ip_address="192.168.1.50",
+ with_analyzer=False,
+ **kwargs):
+ platform = Platform()
+ sys_clk_freq = int(1e6)
+ SoCSDRAM.__init__(self, platform, clk_freq=sys_clk_freq,
+ integrated_rom_size=0x8000,
+ ident="LiteX Simulation", ident_version=True,
+ with_uart=False,
+ **kwargs)
+ # crg
+ self.submodules.crg = CRG(platform.request("sys_clk"))
+
+ # serial
+ self.submodules.uart_phy = uart.RS232PHYModel(platform.request("serial"))
+ self.submodules.uart = uart.UART(self.uart_phy)
+
+ # sdram
+ if with_sdram:
+ sdram_module = MT48LC16M16(100e6, "1:1") # use 100MHz timings
+ phy_settings = PhySettings(
+ memtype="SDR",
+ dfi_databits=16,
+ nphases=1,
+ rdphase=0,
+ wrphase=0,
+ rdcmdphase=0,
+ wrcmdphase=0,
+ cl=2,
+ read_latency=4,
+ write_latency=0
+ )
+ self.submodules.sdrphy = SDRAMPHYModel(sdram_module, phy_settings)
+ self.register_sdram(
+ self.sdrphy,
+ sdram_module.geom_settings,
+ sdram_module.timing_settings)
+ # reduce memtest size for simulation speedup
+ self.add_constant("MEMTEST_DATA_SIZE", 8*1024)
+ self.add_constant("MEMTEST_ADDR_SIZE", 8*1024)
+
+ assert not (with_ethernet and with_etherbone) # FIXME: fix simulator with 2 ethernet interfaces
+
+ # ethernet
+ if with_ethernet:
+ # eth phy
+ self.submodules.ethphy = LiteEthPHYModel(self.platform.request("eth", 0))
+ # eth mac
+ ethmac = LiteEthMAC(phy=self.ethphy, dw=32,
+ interface="wishbone", endianness=self.cpu.endianness)
+ if with_etherbone:
+ ethmac = ClockDomainsRenamer({"eth_tx": "ethphy_eth_tx", "eth_rx": "ethphy_eth_rx"})(ethmac)
+ self.submodules.ethmac = ethmac
+ self.add_wb_slave(mem_decoder(self.mem_map["ethmac"]), self.ethmac.bus)
+ self.add_memory_region("ethmac", self.mem_map["ethmac"] | self.shadow_base, 0x2000)
+
+ # etherbone
+ if with_etherbone:
+ # eth phy
+ self.submodules.etherbonephy = LiteEthPHYModel(self.platform.request("eth", 0)) # FIXME
+ # eth core
+ etherbonecore = LiteEthUDPIPCore(self.etherbonephy,
+ etherbone_mac_address, convert_ip(etherbone_ip_address), sys_clk_freq)
+ if with_ethernet:
+ etherbonecore = ClockDomainsRenamer({"eth_tx": "etherbonephy_eth_tx", "eth_rx": "etherbonephy_eth_rx"})(etherbonecore)
+ self.submodules.etherbonecore = etherbonecore
+ # etherbone
+ self.submodules.etherbone = LiteEthEtherbone(self.etherbonecore.udp, 1234, mode="master")
+ self.add_wb_master(self.etherbone.wishbone.bus)
+
+ # analyzer
+ if with_analyzer:
+ analyzer_signals = [
+ # FIXME: find interesting signals to probe
+ self.cpu.ibus,
+ self.cpu.dbus
+ ]
+ self.submodules.analyzer = LiteScopeAnalyzer(analyzer_signals, 512)
+
+
+def main():
+ parser = argparse.ArgumentParser(description="Generic LiteX SoC Simulation")
+ builder_args(parser)
+ soc_sdram_args(parser)
+ parser.add_argument("--threads", default=1,
+ help="set number of threads (default=1)")
+ parser.add_argument("--rom-init", default=None,
+ help="rom_init file")
+ parser.add_argument("--ram-init", default=None,
+ help="ram_init file")
+ parser.add_argument("--with-sdram", action="store_true",
+ help="enable SDRAM support")
+ parser.add_argument("--with-ethernet", action="store_true",
+ help="enable Ethernet support")
+ parser.add_argument("--with-etherbone", action="store_true",
+ help="enable Etherbone support")
+ parser.add_argument("--with-analyzer", action="store_true",
+ help="enable Analyzer support")
+ parser.add_argument("--trace", action="store_true",
+ help="enable VCD tracing")
+ args = parser.parse_args()
+
+ soc_kwargs = soc_sdram_argdict(args)
+ builder_kwargs = builder_argdict(args)
+
+ sim_config = SimConfig(default_clk="sys_clk")
+ sim_config.add_module("serial2console", "serial")
+
+ cpu_endianness = "big"
+ if "cpu_type" in soc_kwargs:
+ if soc_kwargs["cpu_type"] in ["picorv32", "vexriscv"]:
+ cpu_endianness = "little"
+
+ if args.rom_init:
+ soc_kwargs["integrated_rom_init"] = get_mem_data(args.rom_init, cpu_endianness)
+ if not args.with_sdram:
+ soc_kwargs["integrated_main_ram_size"] = 0x10000000 # 256 MB
+ if args.ram_init is not None:
+ soc_kwargs["integrated_main_ram_init"] = get_mem_data(args.ram_init, cpu_endianness)
+ else:
+ assert args.ram_init is None
+ soc_kwargs["integrated_main_ram_size"] = 0x0
+ if args.with_ethernet:
+ sim_config.add_module("ethernet", "eth", args={"interface": "tap0", "ip": "192.168.1.100"})
+ if args.with_etherbone:
+ sim_config.add_module('ethernet', "eth", args={"interface": "tap1", "ip": "192.168.1.101"})
+
+ soc = SimSoC(
+ with_sdram=args.with_sdram,
+ with_ethernet=args.with_ethernet,
+ with_etherbone=args.with_etherbone,
+ with_analyzer=args.with_analyzer,
+ **soc_kwargs)
+ if args.ram_init is not None:
+ soc.add_constant("ROM_BOOT_ADDRESS", 0x40000000)
+ builder_kwargs["csr_csv"] = "csr.csv"
+ builder = Builder(soc, **builder_kwargs)
+ vns = builder.build(run=False, threads=args.threads, sim_config=sim_config, trace=args.trace)
+ if args.with_analyzer:
+ soc.analyzer.export_csv(vns, "analyzer.csv")
+ builder.build(build=False, threads=args.threads, sim_config=sim_config, trace=args.trace)
+
+
+if __name__ == "__main__":
+ main()
--- /dev/null
+#!/usr/bin/env python3
+
+import sys
+import os
+import time
+import serial
+import threading
+import argparse
+
+
+if sys.platform == "win32":
+ import msvcrt
+ class Console:
+ def configure(self):
+ pass
+
+ def unconfigure(self):
+ pass
+
+ def getkey(self):
+ return msvcrt.getch()
+else:
+ import termios
+ class Console:
+ def __init__(self):
+ self.fd = sys.stdin.fileno()
+ self.default_settings = termios.tcgetattr(self.fd)
+
+ def configure(self):
+ settings = termios.tcgetattr(self.fd)
+ settings[3] = settings[3] & ~termios.ICANON & ~termios.ECHO
+ settings[6][termios.VMIN] = 1
+ settings[6][termios.VTIME] = 0
+ termios.tcsetattr(self.fd, termios.TCSANOW, settings)
+
+ def unconfigure(self):
+ termios.tcsetattr(self.fd, termios.TCSAFLUSH, self.default_settings)
+
+ def getkey(self):
+ return os.read(self.fd, 1)
+
+
+sfl_prompt_req = b"F7: boot from serial\n"
+sfl_prompt_ack = b"\x06"
+
+sfl_magic_req = b"sL5DdSMmkekro\n"
+sfl_magic_ack = b"z6IHG7cYDID6o\n"
+
+# General commands
+sfl_cmd_abort = b"\x00"
+sfl_cmd_load = b"\x01"
+sfl_cmd_jump = b"\x02"
+
+# Replies
+sfl_ack_success = b"K"
+sfl_ack_crcerror = b"C"
+sfl_ack_unknown = b"U"
+sfl_ack_error = b"E"
+
+
+crc16_table = [
+ 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7,
+ 0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF,
+ 0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6,
+ 0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE,
+ 0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485,
+ 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D,
+ 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4,
+ 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC,
+ 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
+ 0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B,
+ 0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12,
+ 0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A,
+ 0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41,
+ 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49,
+ 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70,
+ 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78,
+ 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F,
+ 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
+ 0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E,
+ 0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256,
+ 0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D,
+ 0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
+ 0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C,
+ 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634,
+ 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB,
+ 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3,
+ 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
+ 0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92,
+ 0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9,
+ 0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1,
+ 0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8,
+ 0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0
+]
+
+
+def crc16(l):
+ crc = 0
+ for d in l:
+ crc = crc16_table[((crc >> 8) ^ d) & 0xff] ^ (crc << 8)
+ return crc & 0xffff
+
+
+class SFLFrame:
+ def __init__(self):
+ self.cmd = bytes()
+ self.payload = bytes()
+
+ def compute_crc(self):
+ return crc16(self.cmd + self.payload)
+
+ def encode(self):
+ packet = bytes([len(self.payload)])
+ packet += self.compute_crc().to_bytes(2, "big")
+ packet += self.cmd
+ packet += self.payload
+ return packet
+
+
+class LiteXTerm:
+ def __init__(self, serial_boot, kernel_image, kernel_address):
+ self.serial_boot = serial_boot
+ self.kernel_image = kernel_image
+ self.kernel_address = kernel_address
+
+ self.reader_alive = False
+ self.writer_alive = False
+
+ self.prompt_detect_buffer = bytes(len(sfl_prompt_req))
+ self.magic_detect_buffer = bytes(len(sfl_magic_req))
+
+ self.console = Console()
+
+ def open(self, port, baudrate):
+ if hasattr(self, "port"):
+ return
+ self.port = serial.serial_for_url(port, baudrate)
+
+ def close(self):
+ if not hasattr(self, "port"):
+ return
+ self.port.close()
+ del self.port
+
+ def send_frame(self, frame):
+ retry = 1
+ while retry:
+ self.port.write(frame.encode())
+ # Get the reply from the device
+ reply = self.port.read()
+ if reply == sfl_ack_success:
+ retry = 0
+ elif reply == sfl_ack_crcerror:
+ retry = 1
+ else:
+ print("[TERM] Got unknown reply '{}' from the device, aborting.".format(reply))
+ return 0
+ return 1
+
+ def upload(self, filename, address):
+ with open(filename, "rb") as f:
+ data = f.read()
+ print("[TERM] Uploading {} ({} bytes)...".format(filename, len(data)))
+ current_address = address
+ position = 0
+ length = len(data)
+ start = time.time()
+ while len(data):
+ sys.stdout.write("|{}>{}| {}%\r".format('=' * (20*position//length),
+ ' ' * (20-20*position//length),
+ 100*position//length))
+ sys.stdout.flush()
+ frame = SFLFrame()
+ frame_data = data[:251]
+ frame.cmd = sfl_cmd_load
+ frame.payload = current_address.to_bytes(4, "big")
+ frame.payload += frame_data
+ if self.send_frame(frame) == 0:
+ return
+ current_address += len(frame_data)
+ position += len(frame_data)
+ try:
+ data = data[251:]
+ except:
+ data = []
+ end = time.time()
+ elapsed = end - start
+ print("[TERM] Upload complete ({0:.1f}KB/s).".format(length/(elapsed*1024)))
+ return length
+
+ def boot(self):
+ print("[TERM] Booting the device.")
+ frame = SFLFrame()
+ frame.cmd = sfl_cmd_jump
+ frame.payload = self.kernel_address.to_bytes(4, "big")
+ self.send_frame(frame)
+
+ def detect_prompt(self, data):
+ if len(data):
+ self.prompt_detect_buffer = self.prompt_detect_buffer[1:] + data
+ return self.prompt_detect_buffer == sfl_prompt_req
+ else:
+ return False
+
+ def answer_prompt(self):
+ print("[TERM] Received serial boot prompt from the device.")
+ self.port.write(sfl_prompt_ack)
+
+ def detect_magic(self, data):
+ if len(data):
+ self.magic_detect_buffer = self.magic_detect_buffer[1:] + data
+ return self.magic_detect_buffer == sfl_magic_req
+ else:
+ return False
+
+ def answer_magic(self):
+ print("[TERM] Received firmware download request from the device.")
+ if os.path.exists(self.kernel_image):
+ self.port.write(sfl_magic_ack)
+ self.upload(self.kernel_image, self.kernel_address)
+ self.boot()
+ print("[TERM] Done.");
+
+ def reader(self):
+ try:
+ while self.reader_alive:
+ c = self.port.read()
+ if c == b"\r":
+ sys.stdout.buffer.write(b"\n")
+ else:
+ sys.stdout.buffer.write(c)
+ sys.stdout.flush()
+
+ if self.kernel_image is not None:
+ if self.serial_boot and self.detect_prompt(c):
+ self.answer_prompt()
+ if self.detect_magic(c):
+ self.answer_magic()
+
+ except serial.SerialException:
+ self.reader_alive = False
+ raise
+
+ def start_reader(self):
+ self.reader_alive = True
+ self.reader_thread = threading.Thread(target=self.reader)
+ self.reader_thread.setDaemon(True)
+ self.reader_thread.start()
+
+ def stop_reader(self):
+ self.reader_alive = False
+ self.reader_thread.join()
+
+ def writer(self):
+ try:
+ while self.writer_alive:
+ b = self.console.getkey()
+ if b == b"\x03":
+ self.stop()
+ elif b == b"\n":
+ self.port.write(b"\x0a")
+ else:
+ self.port.write(b)
+ except:
+ self.writer_alive = False
+ raise
+
+ def start_writer(self):
+ self.writer_alive = True
+ self.writer_thread = threading.Thread(target=self.writer)
+ self.writer_thread.setDaemon(True)
+ self.writer_thread.start()
+
+ def stop_writer(self):
+ self.writer_alive = False
+ self.writer_thread.join()
+
+ def start(self):
+ print("[TERM] Starting....")
+ self.start_reader()
+ self.start_writer()
+
+ def stop(self):
+ self.reader_alive = False
+ self.writer_alive = False
+
+ def join(self, writer_only=False):
+ self.writer_thread.join()
+ if not writer_only:
+ self.reader_thread.join()
+
+
+def _get_args():
+ parser = argparse.ArgumentParser()
+ parser.add_argument("port", help="serial port")
+ parser.add_argument("--speed", default=115200, help="serial baudrate")
+ parser.add_argument("--serial-boot", default=False, action='store_true',
+ help="automatically initiate serial boot")
+ parser.add_argument("--kernel", default=None, help="kernel image")
+ parser.add_argument("--kernel-adr", type=lambda a: int(a, 0), default=0x40000000, help="kernel address")
+ return parser.parse_args()
+
+
+def main():
+ args = _get_args()
+ term = LiteXTerm(args.serial_boot, args.kernel, args.kernel_adr)
+ term.console.configure()
+ try:
+ term.open(args.port, args.speed)
+ term.start()
+ term.join(True)
+ except KeyboardInterrupt:
+ term.console.unconfigure()
+ finally:
+ term.console.unconfigure()
+ term.close()
+
+if __name__ == "__main__":
+ main()
--- /dev/null
+import mmap
+
+
+class CommPCIe:
+ def __init__(self, bar, debug=False):
+ self.bar = bar
+ self.debug = debug
+
+ def open(self):
+ if hasattr(self, "sysfs"):
+ return
+ self.sysfs = open(self.bar, "r+b")
+ self.sysfs.flush()
+ self.mmap = mmap.mmap(self.sysfs.fileno(), 0)
+
+ def close(self):
+ if not hasattr(self, "sysfs"):
+ return
+ self.mmap.close()
+ del self.mmap
+ self.sysfs.close()
+ del self.sysfs
+
+ def read(self, addr, length=None):
+ data = []
+ length_int = 1 if length is None else length
+ for i in range(length_int):
+ self.mmap.seek(addr + 4*i)
+ value = int.from_bytes(self.mmap.read(4), byteorder="little")
+ if self.debug:
+ print("read {:08x} @ {:08x}".format(value, addr + 4*i))
+ if length is None:
+ return value
+ data.append(value)
+ return data
+
+ def write(self, addr, data):
+ data = data if isinstance(data, list) else [data]
+ length = len(data)
+ for i, value in enumerate(data):
+ self.mmap[addr + 4*i:addr + 4*(i + 1)] = value.to_bytes(4, byteorder="little")
+ if self.debug:
+ print("write {:08x} @ {:08x}".format(value, addr + 4*i))
--- /dev/null
+import serial
+import struct
+
+
+class CommUART:
+ msg_type = {
+ "write": 0x01,
+ "read": 0x02
+ }
+ def __init__(self, port, baudrate=115200, debug=False):
+ self.port = port
+ self.baudrate = str(baudrate)
+ self.debug = debug
+ self.port = serial.serial_for_url(port, baudrate)
+
+ 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):
+ self._flush()
+ data = []
+ length_int = 1 if length is None else length
+ self._write([self.msg_type["read"], length_int])
+ self._write(list((addr//4).to_bytes(4, byteorder="big")))
+ for i in range(length_int):
+ value = int.from_bytes(self._read(4), "big")
+ if self.debug:
+ print("read {:08x} @ {:08x}".format(value, addr + 4*i))
+ if length is None:
+ return value
+ data.append(value)
+ return data
+
+ def write(self, addr, data):
+ self._flush()
+ data = data if isinstance(data, list) else [data]
+ length = len(data)
+ offset = 0
+ while length:
+ size = min(length, 8)
+ self._write([self.msg_type["write"], size])
+ self._write(list(((addr+offset)//4).to_bytes(4, byteorder="big")))
+ for i, value in enumerate(data[offset:offset+size]):
+ self._write(list(value.to_bytes(4, byteorder="big")))
+ if self.debug:
+ print("write {:08x} @ {:08x}".format(value, addr + offset, 4*i))
+ offset += size
+ length -= size
--- /dev/null
+import socket
+
+from litex.tools.remote.etherbone import EtherbonePacket, EtherboneRecord
+from litex.tools.remote.etherbone import EtherboneReads, EtherboneWrites
+
+
+class CommUDP:
+ def __init__(self, server="192.168.1.50", port=1234, debug=False):
+ self.server = server
+ self.port = port
+ self.debug = debug
+
+ def open(self):
+ if hasattr(self, "tx_socket"):
+ return
+ self.tx_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+ self.rx_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+ self.rx_socket.bind(("", self.port))
+
+ def close(self):
+ if not hasattr(self, "tx_socket"):
+ return
+ self.tx_socket.close()
+ del self.tx_socket
+ self.rx_socket.close()
+ del self.rx_socket
+
+ def read(self, addr, length=None):
+ length_int = 1 if length is None else length
+ record = EtherboneRecord()
+ record.reads = EtherboneReads(addrs=[addr+4*j for j in range(length_int)])
+ record.rcount = len(record.reads)
+
+ packet = EtherbonePacket()
+ packet.records = [record]
+ packet.encode()
+ self.tx_socket.sendto(bytes(packet), (self.server, self.port))
+
+ datas, dummy = self.rx_socket.recvfrom(8192)
+ packet = EtherbonePacket(datas)
+ packet.decode()
+ datas = packet.records.pop().writes.get_datas()
+ if self.debug:
+ for i, value in enumerate(datas):
+ print("read {:08x} @ {:08x}".format(value, addr + 4*i))
+ return datas[0] if length is None else datas
+
+ def write(self, addr, datas):
+ datas = datas if isinstance(datas, list) else [datas]
+ length = len(datas)
+ record = EtherboneRecord()
+ record.writes = EtherboneWrites(base_addr=addr, datas=iter(datas))
+ record.wcount = len(record.writes)
+
+ packet = EtherbonePacket()
+ packet.records = [record]
+ packet.encode()
+ self.tx_socket.sendto(bytes(packet), (self.server, self.port))
+
+ if self.debug:
+ for i, value in enumerate(datas):
+ print("write {:08x} @ {:08x}".format(value, addr + 4*i))
--- /dev/null
+import usb.core
+import time
+
+# Wishbone USB Protocol Bridge
+# ============================
+#
+# This module implements a bridge to connect LiteX to the target system's
+# Wishbone bus via USB. It uses `vendor` packets to communicate, which are
+# normally reserved. Since we're the vendors of this USB protocol, we take
+# advantage of this packet type to implement the bridge.
+#
+# All traffic goes to/from USB EP0, which is guaranteed to exist regardless
+# of the user's device implementation. The 8th bit of the first SETUP DATA
+# transaction contains all the information we need to mark this as a
+# Wishbone packet.
+#
+# Packets going to EP0 always start with a SETUP packet, followed by an IN
+# or an OUT packet, followed by an OUT or an IN packet.
+#
+# The SETUP packet looks like this:
+#
+# +----+----+----------+----+----+
+# | C0 | 00 | ADDRESS | 04 | 00 | read packet
+# +----+----+----------+----+----+
+# 1 1 4 1 1
+#
+# +----+----+----------+----+----+
+# | 40 | 00 | ADDRESS | 04 | 00 | write packet
+# +----+----+----------+----+----+
+# 1 1 4 1 1
+#
+# If the transaction is a "read" transaction, the device responds with an OUT
+# packet with the data. If the transaction is a "write" transaction, the host
+# responds with an IN packet with the data.
+#
+# Much like other Wishbone bridges, there are two types of packets. The first
+# byte indicates what type of packet it is, and that it is a Wishbone Bridge
+# packet. This is the value "0x40" (VENDOR type packet destined for DEVICE)
+# with the "Data Phase Transfer" bit either set or cleared:
+# - Read: 0xc0
+# - Write: 0x40
+#
+# The next byte is bRequest, which in the current implementation is unused.
+# Set this value to 0.
+#
+# The next four bytes form the wValue and wIndex values of the SETUP token.
+# We reuse these two 16-bit values as a single 32-bit ADDRESS packet. Note that
+# USB is big endian.
+#
+# Finally, the last two bytes indicate the length of the transaction. Since
+# we only support 32-bit reads and writes, this is always 4. On big endian
+# USB, this has the value {04, 00}.
+
+class CommUSB:
+ def __init__(self, vid=None, pid=None, max_retries=10, debug=False):
+ self.vid = vid
+ self.pid = pid
+ self.debug = debug
+ self.max_retries = max_retries
+ self.MAX_RECURSION_COUNT = 5
+
+ def open(self):
+ if hasattr(self, "dev"):
+ return
+ for t in range(self.max_retries):
+ args = {}
+ if self.vid is not None:
+ args['idVendor'] = self.vid
+ if self.pid is not None:
+ args['idProduct'] = self.pid
+ self.dev = usb.core.find(**args)
+ if self.dev is not None:
+ if self.debug:
+ print("device connected after {} tries".format(t+1))
+ return True
+ del self.dev
+ time.sleep(0.2 * t)
+ print("unable to find usb device after {} tries".format(self.max_retries))
+ return False
+
+
+ def close(self):
+ if not hasattr(self, "dev"):
+ return
+ del self.dev
+
+ def read(self, addr, length=None):
+ data = []
+ length_int = 1 if length is None else length
+ for i in range(length_int):
+ value = self.usb_read(addr)
+ # Note that sometimes, the value ends up as None when the device
+ # disconnects during a transaction. Paper over this fact by
+ # replacing it with a sentinal.
+ if value is None:
+ value = 0xffffffff
+ if self.debug:
+ print("read {:08x} @ {:08x}".format(value, addr))
+ if length is None:
+ return value
+ data.append(value)
+ return data
+
+ def usb_read(self, addr, depth=0):
+ try:
+ value = self.dev.ctrl_transfer(bmRequestType=0xc0,
+ bRequest=0x00,
+ wValue=addr & 0xffff,
+ wIndex=(addr >> 16) & 0xffff,
+ data_or_wLength=4)
+ if value is None:
+ raise TypeError
+ return int.from_bytes(value, byteorder="little")
+ except (usb.core.USBError, TypeError):
+ self.close()
+ self.open()
+ if depth < self.MAX_RECURSION_COUNT:
+ return self.usb_read(addr, depth+1)
+
+ def write(self, addr, data):
+ data = data if isinstance(data, list) else [data]
+ length = len(data)
+ for i, value in enumerate(data):
+ self.usb_write(addr, value)
+ if self.debug:
+ print("write {:08x} @ {:08x}".format(value, addr + 4*i))
+
+ def usb_write(self, addr, value, depth=0):
+ try:
+ self.dev.ctrl_transfer(bmRequestType=0x40, bRequest=0x00,
+ wValue=addr & 0xffff,
+ wIndex=(addr >> 16) & 0xffff,
+ data_or_wLength=bytes([(value >> 0) & 0xff,
+ (value >> 8) & 0xff,
+ (value >> 16) & 0xff,
+ (value >> 24) & 0xff]
+ ), timeout=None)
+ except usb.core.USBError:
+ self.close()
+ self.open()
+ if depth < self.MAX_RECURSION_COUNT:
+ return self.usb_write(addr, value, depth+1)
--- /dev/null
+import csv
+
+
+class CSRElements:
+ def __init__(self, d):
+ self.__dict__.update(d)
+
+ @property
+ def d(self):
+ return self.__dict__
+
+ def __getattr__(self, attr):
+ try:
+ return self.__dict__[attr]
+ except KeyError:
+ pass
+ raise AttributeError("No such element " + attr)
+
+
+class CSRRegister:
+ def __init__(self, readfn, writefn, name, addr, length, data_width, mode):
+ self.readfn = readfn
+ self.writefn = writefn
+ self.name = name
+ self.addr = addr
+ self.length = length
+ self.data_width = data_width
+ self.mode = mode
+
+ def read(self):
+ if self.mode not in ["rw", "ro"]:
+ raise KeyError(self.name + "register not readable")
+ datas = self.readfn(self.addr, length=self.length)
+ if isinstance(datas, int):
+ return datas
+ else:
+ data = 0
+ for i in range(self.length):
+ data = data << self.data_width
+ data |= datas[i]
+ return data
+
+ def write(self, value):
+ if self.mode not in ["rw", "wo"]:
+ raise KeyError(self.name + "register not writable")
+ datas = []
+ for i in range(self.length):
+ datas.append((value >> ((self.length-1-i)*self.data_width)) & (2**self.data_width-1))
+ self.writefn(self.addr, datas)
+
+
+class CSRMemoryRegion:
+ def __init__(self, base, size):
+ self.base = base
+ self.size = size
+
+
+class CSRBuilder:
+ def __init__(self, comm, csr_csv, csr_data_width=None):
+ self.constants = self.build_constants(csr_csv)
+
+ # Load csr_data_width from the constants, otherwise it must be provided
+ constant_csr_data_width = self.constants.d.get('csr_data_width', None)
+ if csr_data_width is None:
+ csr_data_width = constant_csr_data_width
+ if csr_data_width is None:
+ raise KeyError('csr_data_width not found in constants, please provide!')
+ if csr_data_width != constant_csr_data_width:
+ raise KeyError('csr_data_width of {} provided but {} found in constants'.format(
+ csr_data_width, constant_csr_data_width))
+
+ self.csr_data_width = csr_data_width
+ self.bases = self.build_bases(csr_csv)
+ self.regs = self.build_registers(csr_csv, comm.read, comm.write)
+ self.mems = self.build_memories(csr_csv)
+
+ def build_bases(self, csr_csv):
+ csv_reader = csv.reader(open(csr_csv), delimiter=',', quotechar='#')
+ d = {}
+ for item in csv_reader:
+ group, name, addr, dummy0, dummy1 = item
+ if group == "csr_base":
+ d[name] = int(addr.replace("0x", ""), 16)
+ return CSRElements(d)
+
+ def build_registers(self, csr_csv, readfn, writefn):
+ csv_reader = csv.reader(open(csr_csv), delimiter=',', quotechar='#')
+ d = {}
+ for item in csv_reader:
+ group, name, addr, length, mode = item
+ if group == "csr_register":
+ addr = int(addr.replace("0x", ""), 16)
+ length = int(length)
+ d[name] = CSRRegister(readfn, writefn, name, addr, length, self.csr_data_width, mode)
+ return CSRElements(d)
+
+ def build_constants(self, csr_csv):
+ csv_reader = csv.reader(open(csr_csv), delimiter=',', quotechar='#')
+ d = {}
+ for item in csv_reader:
+ group, name, value, dummy0, dummy1 = item
+ if group == "constant":
+ try:
+ d[name] = int(value)
+ except:
+ d[name] = value
+ return CSRElements(d)
+
+ def build_memories(self, csr_csv):
+ csv_reader = csv.reader(open(csr_csv), delimiter=',', quotechar='#')
+ d = {}
+ for item in csv_reader:
+ group, name, base, size, dummy1 = item
+ if group == "memory_region":
+ d[name] = CSRMemoryRegion(int(base, 16), int(size))
+ return CSRElements(d)
--- /dev/null
+import math
+import struct
+
+from litex.soc.interconnect.stream_packet import HeaderField, Header
+
+
+etherbone_magic = 0x4e6f
+etherbone_version = 1
+etherbone_packet_header_length = 8
+etherbone_packet_header_fields = {
+ "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
+
+ "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)
+
+# 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
+
+ "byte_enable": HeaderField(1, 0, 8), # Select
+
+ "wcount": HeaderField(2, 0, 8), # Writes
+
+ "rcount": HeaderField(3, 0, 8), # Reads
+}
+etherbone_record_header = Header(etherbone_record_header_fields,
+ etherbone_record_header_length,
+ swap_field_bytes=True)
+
+
+def split_bytes(v, n, endianness="big"):
+ r = []
+ return v.to_bytes(n, byteorder=endianness)
+
+
+def merge_bytes(b, endianness="big"):
+ return int.from_bytes(b, endianness)
+
+
+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)
+
+
+class Packet(list):
+ def __init__(self, init=[]):
+ self.ongoing = False
+ self.done = False
+ for data in init:
+ self.append(data)
+
+
+class EtherboneWrite:
+ def __init__(self, data):
+ self.data = data
+
+ def __repr__(self):
+ return "WR32 0x{:08x}".format(self.data)
+
+
+class EtherboneRead:
+ def __init__(self, addr):
+ self.addr = addr
+
+ def __repr__(self):
+ return "RD32 @ 0x{:08x}".format(self.addr)
+
+
+class EtherboneWrites(Packet):
+ def __init__(self, init=[], base_addr=0, datas=[]):
+ Packet.__init__(self, init)
+ self.base_addr = base_addr
+ self.writes = []
+ self.encoded = init != []
+ for data in datas:
+ self.add(EtherboneWrite(data))
+
+ def add(self, write):
+ self.writes.append(write)
+
+ def get_datas(self):
+ datas = []
+ for write in self.writes:
+ datas.append(write.data)
+ return datas
+
+ def encode(self):
+ if self.encoded:
+ raise ValueError
+ 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)
+ self.encoded = True
+
+ def decode(self):
+ if not self.encoded:
+ raise ValueError
+ 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)))
+ self.encoded = False
+
+ def __repr__(self):
+ r = "Writes\n"
+ r += "--------\n"
+ r += "BaseAddr @ 0x{:08x}\n".format(self.base_addr)
+ for write in self.writes:
+ r += write.__repr__() + "\n"
+ return r
+
+
+class EtherboneReads(Packet):
+ def __init__(self, init=[], base_ret_addr=0, addrs=[]):
+ Packet.__init__(self, init)
+ self.base_ret_addr = base_ret_addr
+ self.reads = []
+ self.encoded = init != []
+ for addr in addrs:
+ self.add(EtherboneRead(addr))
+
+ def add(self, read):
+ self.reads.append(read)
+
+ def get_addrs(self):
+ addrs = []
+ for read in self.reads:
+ addrs.append(read.addr)
+ return addrs
+
+ def encode(self):
+ if self.encoded:
+ raise ValueError
+ 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)
+ self.encoded = True
+
+ def decode(self):
+ if not self.encoded:
+ raise ValueError
+ 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)))
+ self.encoded = False
+
+ def __repr__(self):
+ r = "Reads\n"
+ r += "--------\n"
+ r += "BaseRetAddr @ 0x{:08x}\n".format(self.base_ret_addr)
+ for read in self.reads:
+ r += read.__repr__() + "\n"
+ return r
+
+
+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.byte_enable = 0xf
+ self.wcount = 0
+ self.rcount = 0
+ self.encoded = init != []
+
+
+ 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):
+ if not self.encoded:
+ raise ValueError
+ header = []
+ for byte in self[:etherbone_record_header.length]:
+ header.append(self.pop(0))
+ for k, v in sorted(etherbone_record_header.fields.items()):
+ setattr(self, k, get_field_data(v, header))
+ self.writes = self.get_writes()
+ if self.writes is not None:
+ self.writes.decode()
+ self.reads = self.get_reads()
+ if self.reads is not None:
+ self.reads.decode()
+ self.encoded = False
+
+ def set_writes(self, writes):
+ self.wcount = len(writes.writes)
+ writes.encode()
+ for byte in writes:
+ self.append(byte)
+
+ def set_reads(self, reads):
+ self.rcount = len(reads.reads)
+ reads.encode()
+ for byte in reads:
+ self.append(byte)
+
+ def encode(self):
+ if self.encoded:
+ raise ValueError
+ if self.writes is not None:
+ self.set_writes(self.writes)
+ if self.reads is not None:
+ self.set_reads(self.reads)
+ header = 0
+ for k, v in sorted(etherbone_record_header.fields.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.length):
+ self.insert(0, d)
+ self.encoded = True
+
+ def __repr__(self, n=0):
+ r = "Record {}\n".format(n)
+ r += "--------\n"
+ if self.encoded:
+ for d in self:
+ r += "{:02x}".format(d)
+ else:
+ for k in sorted(etherbone_record_header.fields.keys()):
+ r += k + " : 0x{:0x}\n".format(getattr(self, k))
+ if self.wcount != 0:
+ r += self.writes.__repr__()
+ if self.rcount != 0:
+ r += self.reads.__repr__()
+ return r
+
+
+class EtherbonePacket(Packet):
+ def __init__(self, init=[]):
+ Packet.__init__(self, init)
+ self.encoded = init != []
+ self.records = []
+
+ 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
+
+ def get_records(self):
+ records = []
+ done = False
+ payload = self
+ while len(payload) != 0:
+ record = EtherboneRecord(payload)
+ record.decode()
+ records.append(record)
+ payload = record[:]
+ return records
+
+ def decode(self):
+ if not self.encoded:
+ raise ValueError
+ header = []
+ for byte in self[:etherbone_packet_header.length]:
+ header.append(self.pop(0))
+ for k, v in sorted(etherbone_packet_header.fields.items()):
+ setattr(self, k, get_field_data(v, header))
+ self.records = self.get_records()
+ self.encoded = False
+
+ def set_records(self, records):
+ for record in records:
+ record.encode()
+ for byte in record:
+ self.append(byte)
+
+ def encode(self):
+ if self.encoded:
+ raise ValueError
+ self.set_records(self.records)
+ header = 0
+ for k, v in sorted(etherbone_packet_header.fields.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_packet_header.length):
+ self.insert(0, d)
+ self.encoded = True
+
+ def __repr__(self):
+ r = "Packet\n"
+ r += "--------\n"
+ if self.encoded:
+ for d in self:
+ r += "{:02x}".format(d)
+ else:
+ for k in sorted(etherbone_packet_header.fields.keys()):
+ r += k + " : 0x{:0x}\n".format(getattr(self, k))
+ for i, record in enumerate(self.records):
+ r += record.__repr__(i)
+ return r
+
+
+class EtherboneIPC:
+ def send_packet(self, socket, packet):
+ socket.sendall(bytes(packet))
+
+ def receive_packet(self, socket):
+ header_length = etherbone_packet_header_length + etherbone_record_header_length
+ packet = bytes()
+ while len(packet) < header_length:
+ chunk = socket.recv(header_length - len(packet))
+ if len(chunk) == 0:
+ return 0
+ else:
+ packet += chunk
+ wcount, rcount = struct.unpack(">BB", packet[header_length-2:])
+ counts = wcount + rcount
+ packet_size = header_length + 4*(counts + 1)
+ while len(packet) < packet_size:
+ chunk = socket.recv(packet_size - len(packet))
+ if len(chunk) == 0:
+ return 0
+ else:
+ packet += chunk
+ return packet
+++ /dev/null
-#!/usr/bin/env python3
-import os
-import sys
-import json
-
-from litex.build import tools
-
-def main():
- if len(sys.argv) < 2:
- print("usage: litex_read_verilog verilog_file [module]")
- exit(1)
-
- verilog_file = sys.argv[1]
- json_file = verilog_file + ".json"
- module = None if len(sys.argv) < 3 else sys.argv[2]
-
- # use yosys to convert verilog to json
- yosys_v2j = "\n".join([
- "read_verilog -sv {}".format(verilog_file),
- "write_json {}.json".format(verilog_file)
- ])
- tools.write_to_file("yosys_v2j.ys", yosys_v2j)
- os.system("yosys -q yosys_v2j.ys")
-
- # load json and convert to migen module
- f = open(json_file, "r")
- j = json.load(f)
-
- # create list of modules
- modules = [module] if module is not None else j["modules"].keys()
-
- # create migen definitions
- for module in modules:
- migen_def = []
- migen_def.append("class {}(Module):".format(module))
- migen_def.append(" "*4 + "def __init__(self):")
- for name, info in j["modules"][module]["ports"].items():
- length = "" if len(info["bits"]) == 1 else len(info["bits"])
- migen_def.append(" " * 8 + "self.{} = Signal({})".format(name, length))
- migen_def.append("")
- migen_def.append(" "*8 + "# # #")
- migen_def.append("")
- migen_def.append(" "*8 + "self.specials += Instance(\"{}\",".format(module))
- for name, info in j["modules"][module]["ports"].items():
- io_prefix = {
- "input": "i",
- "output": "o",
- "inout": "io"
- }[info["direction"]]
- migen_def.append(" "*12 + "{}_{}=self.{},".format(io_prefix, name, name))
- migen_def.append(" "*8 + ")")
- migen_def.append("")
- print("\n".join(migen_def))
-
- # keep things clean after us
- os.system("rm " + json_file)
-
-
-if __name__ == "__main__":
- main()
+++ /dev/null
-#!/usr/bin/env python3
-
-import argparse
-
-import sys
-import socket
-import time
-import threading
-
-from litex.soc.tools.remote.etherbone import EtherbonePacket, EtherboneRecord, EtherboneWrites
-from litex.soc.tools.remote.etherbone import EtherboneIPC
-
-
-class RemoteServer(EtherboneIPC):
- def __init__(self, comm, bind_ip, bind_port=1234):
- self.comm = comm
- self.bind_ip = bind_ip
- self.bind_port = bind_port
- self.lock = False
-
- def open(self):
- if hasattr(self, "socket"):
- return
- self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
- self.socket.bind((self.bind_ip, self.bind_port))
- print("tcp port: {:d}".format(self.bind_port))
- self.socket.listen(1)
- self.comm.open()
-
- def close(self):
- self.comm.close()
- if not hasattr(self, "socket"):
- return
- self.socket.close()
- del self.socket
-
- def _serve_thread(self):
- while True:
- client_socket, addr = self.socket.accept()
- print("Connected with " + addr[0] + ":" + str(addr[1]))
- try:
- while True:
- try:
- packet = self.receive_packet(client_socket)
- if packet == 0:
- break
- except:
- break
- packet = EtherbonePacket(packet)
- packet.decode()
-
- record = packet.records.pop()
-
- # wait for lock
- while self.lock:
- time.sleep(0.01)
-
- # set lock
- self.lock = True
-
- # handle writes:
- if record.writes != None:
- self.comm.write(record.writes.base_addr, record.writes.get_datas())
-
- # handle reads
- if record.reads != None:
- reads = []
- for addr in record.reads.get_addrs():
- reads.append(self.comm.read(addr))
-
- record = EtherboneRecord()
- record.writes = EtherboneWrites(datas=reads)
- record.wcount = len(record.writes)
-
- packet = EtherbonePacket()
- packet.records = [record]
- packet.encode()
- self.send_packet(client_socket, packet)
-
- # release lock
- self.lock = False
-
- finally:
- print("Disconnect")
- client_socket.close()
-
- def start(self, nthreads):
- for i in range(nthreads):
- self.serve_thread = threading.Thread(target=self._serve_thread)
- self.serve_thread.setDaemon(True)
- self.serve_thread.start()
-
-
-def main():
- print("LiteX remote server")
- parser = argparse.ArgumentParser()
- # Common arguments
- parser.add_argument("--bind-ip", default="localhost",
- help="Host bind address")
- parser.add_argument("--bind-port", default=1234,
- help="Host bind port")
-
- # UART arguments
- parser.add_argument("--uart", action="store_true",
- help="Select UART interface")
- parser.add_argument("--uart-port", default=None,
- help="Set UART port")
- parser.add_argument("--uart-baudrate", default=115200,
- help="Set UART baudrate")
-
- # UDP arguments
- parser.add_argument("--udp", action="store_true",
- help="Select UDP interface")
- parser.add_argument("--udp-ip", default="192.168.1.50",
- help="Set UDP remote IP address")
- parser.add_argument("--udp-port", default=1234,
- help="Set UDP remote port")
-
- # PCIe arguments
- parser.add_argument("--pcie", action="store_true",
- help="Select PCIe interface")
- parser.add_argument("--pcie-bar", default=None,
- help="Set PCIe BAR")
-
- # USB arguments
- parser.add_argument("--usb", action="store_true",
- help="Select USB interface")
- parser.add_argument("--usb-vid", default=None,
- help="Set USB vendor ID")
- parser.add_argument("--usb-pid", default=None,
- help="Set USB product ID")
- parser.add_argument("--usb-max-retries", default=10,
- help="Number of times to try reconnecting to USB")
- args = parser.parse_args()
-
-
- if args.uart:
- from litex.soc.tools.remote import CommUART
- if args.uart_port is None:
- print("Need to specify --uart-port, exiting.")
- exit()
- uart_port = args.uart_port
- uart_baudrate = int(float(args.uart_baudrate))
- print("[CommUART] port: {} / baudrate: {} / ".format(uart_port, uart_baudrate), end="")
- comm = CommUART(uart_port, uart_baudrate)
- elif args.udp:
- from litex.soc.tools.remote import CommUDP
- udp_ip = args.udp_ip
- udp_port = int(args.udp_port)
- print("[CommUDP] ip: {} / port: {} / ".format(udp_ip, udp_port), end="")
- comm = CommUDP(udp_ip, udp_port)
- elif args.pcie:
- from litex.soc.tools.remote import CommPCIe
- pcie_bar = args.pcie_bar
- if args.pcie_bar is None:
- print("Need to speficy --pcie-bar, exiting.")
- exit()
- print("[CommPCIe] bar: {} / ".format(args.pcie_bar), end="")
- comm = CommPCIe(args.pcie_bar)
- elif args.usb:
- from litex.soc.tools.remote import CommUSB
- if args.usb_pid is None and args.usb_vid is None:
- print("Need to speficy --usb-vid or --usb-pid, exiting.")
- exit()
- print("[CommUSB] vid: {} / pid: {} / ".format(args.usb_vid, args.usb_pid), end="")
- pid = args.usb_pid
- if pid is not None:
- pid = int(pid, base=0)
- vid = args.usb_vid
- if vid is not None:
- vid = int(vid, base=0)
- comm = CommUSB(vid=vid, pid=pid, max_retries=args.usb_max_retries)
- else:
- parser.print_help()
- exit()
-
- server = RemoteServer(comm, args.bind_ip, int(args.bind_port))
- server.open()
- server.start(4)
- try:
- import time
- while True: time.sleep(100)
- except KeyboardInterrupt:
- pass
-
-if __name__ == "__main__":
- main()
+++ /dev/null
-#!/usr/bin/env python3
-
-import argparse
-
-from migen import *
-from migen.genlib.io import CRG
-
-from litex.build.generic_platform import *
-from litex.build.sim import SimPlatform
-from litex.build.sim.config import SimConfig
-
-from litex.soc.integration.soc_core import *
-from litex.soc.integration.soc_sdram import *
-from litex.soc.integration.builder import *
-from litex.soc.cores import uart
-from litex.soc.integration.soc_core import mem_decoder
-
-from litedram.common import PhySettings
-from litedram.modules import MT48LC16M16
-from litedram.phy.model import SDRAMPHYModel
-
-from liteeth.common import convert_ip
-from liteeth.phy.model import LiteEthPHYModel
-from liteeth.core.mac import LiteEthMAC
-from liteeth.core import LiteEthUDPIPCore
-from liteeth.frontend.etherbone import LiteEthEtherbone
-
-from litescope import LiteScopeAnalyzer
-
-
-class SimPins(Pins):
- def __init__(self, n=1):
- Pins.__init__(self, "s "*n)
-
-
-_io = [
- ("sys_clk", 0, SimPins(1)),
- ("sys_rst", 0, SimPins(1)),
- ("serial", 0,
- Subsignal("source_valid", SimPins()),
- Subsignal("source_ready", SimPins()),
- Subsignal("source_data", SimPins(8)),
-
- Subsignal("sink_valid", SimPins()),
- Subsignal("sink_ready", SimPins()),
- Subsignal("sink_data", SimPins(8)),
- ),
- ("eth_clocks", 0,
- Subsignal("none", SimPins()),
- ),
- ("eth", 0,
- Subsignal("source_valid", SimPins()),
- Subsignal("source_ready", SimPins()),
- Subsignal("source_data", SimPins(8)),
-
- Subsignal("sink_valid", SimPins()),
- Subsignal("sink_ready", SimPins()),
- Subsignal("sink_data", SimPins(8)),
- ),
- ("eth_clocks", 1,
- Subsignal("none", SimPins()),
- ),
- ("eth", 1,
- Subsignal("source_valid", SimPins()),
- Subsignal("source_ready", SimPins()),
- Subsignal("source_data", SimPins(8)),
-
- Subsignal("sink_valid", SimPins()),
- Subsignal("sink_ready", SimPins()),
- Subsignal("sink_data", SimPins(8)),
- ),
-]
-
-
-class Platform(SimPlatform):
- default_clk_name = "sys_clk"
- default_clk_period = 1000 # ~ 1MHz
-
- def __init__(self):
- SimPlatform.__init__(self, "SIM", _io)
-
- def do_finalize(self, fragment):
- pass
-
-
-class SimSoC(SoCSDRAM):
- csr_peripherals = [
- "ethphy",
- "ethmac",
-
- "etherbonephy",
- "etherbonecore",
-
- "analyzer",
- ]
- csr_map_update(SoCSDRAM.csr_map, csr_peripherals)
-
- interrupt_map = {
- "ethmac": 3,
- }
- interrupt_map.update(SoCSDRAM.interrupt_map)
-
- mem_map = {
- "ethmac": 0x30000000, # (shadow @0xb0000000)
- }
- mem_map.update(SoCSDRAM.mem_map)
-
- def __init__(self,
- with_sdram=False,
- with_ethernet=False,
- with_etherbone=False, etherbone_mac_address=0x10e2d5000000, etherbone_ip_address="192.168.1.50",
- with_analyzer=False,
- **kwargs):
- platform = Platform()
- sys_clk_freq = int(1e6)
- SoCSDRAM.__init__(self, platform, clk_freq=sys_clk_freq,
- integrated_rom_size=0x8000,
- ident="LiteX Simulation", ident_version=True,
- with_uart=False,
- **kwargs)
- # crg
- self.submodules.crg = CRG(platform.request("sys_clk"))
-
- # serial
- self.submodules.uart_phy = uart.RS232PHYModel(platform.request("serial"))
- self.submodules.uart = uart.UART(self.uart_phy)
-
- # sdram
- if with_sdram:
- sdram_module = MT48LC16M16(100e6, "1:1") # use 100MHz timings
- phy_settings = PhySettings(
- memtype="SDR",
- dfi_databits=16,
- nphases=1,
- rdphase=0,
- wrphase=0,
- rdcmdphase=0,
- wrcmdphase=0,
- cl=2,
- read_latency=4,
- write_latency=0
- )
- self.submodules.sdrphy = SDRAMPHYModel(sdram_module, phy_settings)
- self.register_sdram(
- self.sdrphy,
- sdram_module.geom_settings,
- sdram_module.timing_settings)
- # reduce memtest size for simulation speedup
- self.add_constant("MEMTEST_DATA_SIZE", 8*1024)
- self.add_constant("MEMTEST_ADDR_SIZE", 8*1024)
-
- assert not (with_ethernet and with_etherbone) # FIXME: fix simulator with 2 ethernet interfaces
-
- # ethernet
- if with_ethernet:
- # eth phy
- self.submodules.ethphy = LiteEthPHYModel(self.platform.request("eth", 0))
- # eth mac
- ethmac = LiteEthMAC(phy=self.ethphy, dw=32,
- interface="wishbone", endianness=self.cpu.endianness)
- if with_etherbone:
- ethmac = ClockDomainsRenamer({"eth_tx": "ethphy_eth_tx", "eth_rx": "ethphy_eth_rx"})(ethmac)
- self.submodules.ethmac = ethmac
- self.add_wb_slave(mem_decoder(self.mem_map["ethmac"]), self.ethmac.bus)
- self.add_memory_region("ethmac", self.mem_map["ethmac"] | self.shadow_base, 0x2000)
-
- # etherbone
- if with_etherbone:
- # eth phy
- self.submodules.etherbonephy = LiteEthPHYModel(self.platform.request("eth", 0)) # FIXME
- # eth core
- etherbonecore = LiteEthUDPIPCore(self.etherbonephy,
- etherbone_mac_address, convert_ip(etherbone_ip_address), sys_clk_freq)
- if with_ethernet:
- etherbonecore = ClockDomainsRenamer({"eth_tx": "etherbonephy_eth_tx", "eth_rx": "etherbonephy_eth_rx"})(etherbonecore)
- self.submodules.etherbonecore = etherbonecore
- # etherbone
- self.submodules.etherbone = LiteEthEtherbone(self.etherbonecore.udp, 1234, mode="master")
- self.add_wb_master(self.etherbone.wishbone.bus)
-
- # analyzer
- if with_analyzer:
- analyzer_signals = [
- # FIXME: find interesting signals to probe
- self.cpu.ibus,
- self.cpu.dbus
- ]
- self.submodules.analyzer = LiteScopeAnalyzer(analyzer_signals, 512)
-
-
-def main():
- parser = argparse.ArgumentParser(description="Generic LiteX SoC Simulation")
- builder_args(parser)
- soc_sdram_args(parser)
- parser.add_argument("--threads", default=1,
- help="set number of threads (default=1)")
- parser.add_argument("--rom-init", default=None,
- help="rom_init file")
- parser.add_argument("--ram-init", default=None,
- help="ram_init file")
- parser.add_argument("--with-sdram", action="store_true",
- help="enable SDRAM support")
- parser.add_argument("--with-ethernet", action="store_true",
- help="enable Ethernet support")
- parser.add_argument("--with-etherbone", action="store_true",
- help="enable Etherbone support")
- parser.add_argument("--with-analyzer", action="store_true",
- help="enable Analyzer support")
- parser.add_argument("--trace", action="store_true",
- help="enable VCD tracing")
- args = parser.parse_args()
-
- soc_kwargs = soc_sdram_argdict(args)
- builder_kwargs = builder_argdict(args)
-
- sim_config = SimConfig(default_clk="sys_clk")
- sim_config.add_module("serial2console", "serial")
-
- cpu_endianness = "big"
- if "cpu_type" in soc_kwargs:
- if soc_kwargs["cpu_type"] in ["picorv32", "vexriscv"]:
- cpu_endianness = "little"
-
- if args.rom_init:
- soc_kwargs["integrated_rom_init"] = get_mem_data(args.rom_init, cpu_endianness)
- if not args.with_sdram:
- soc_kwargs["integrated_main_ram_size"] = 0x10000000 # 256 MB
- if args.ram_init is not None:
- soc_kwargs["integrated_main_ram_init"] = get_mem_data(args.ram_init, cpu_endianness)
- else:
- assert args.ram_init is None
- soc_kwargs["integrated_main_ram_size"] = 0x0
- if args.with_ethernet:
- sim_config.add_module("ethernet", "eth", args={"interface": "tap0", "ip": "192.168.1.100"})
- if args.with_etherbone:
- sim_config.add_module('ethernet', "eth", args={"interface": "tap1", "ip": "192.168.1.101"})
-
- soc = SimSoC(
- with_sdram=args.with_sdram,
- with_ethernet=args.with_ethernet,
- with_etherbone=args.with_etherbone,
- with_analyzer=args.with_analyzer,
- **soc_kwargs)
- if args.ram_init is not None:
- soc.add_constant("ROM_BOOT_ADDRESS", 0x40000000)
- builder_kwargs["csr_csv"] = "csr.csv"
- builder = Builder(soc, **builder_kwargs)
- vns = builder.build(run=False, threads=args.threads, sim_config=sim_config, trace=args.trace)
- if args.with_analyzer:
- soc.analyzer.export_csv(vns, "analyzer.csv")
- builder.build(build=False, threads=args.threads, sim_config=sim_config, trace=args.trace)
-
-
-if __name__ == "__main__":
- main()
+++ /dev/null
-#!/usr/bin/env python3
-
-import sys
-import os
-import time
-import serial
-import threading
-import argparse
-
-
-if sys.platform == "win32":
- import msvcrt
- class Console:
- def configure(self):
- pass
-
- def unconfigure(self):
- pass
-
- def getkey(self):
- return msvcrt.getch()
-else:
- import termios
- class Console:
- def __init__(self):
- self.fd = sys.stdin.fileno()
- self.default_settings = termios.tcgetattr(self.fd)
-
- def configure(self):
- settings = termios.tcgetattr(self.fd)
- settings[3] = settings[3] & ~termios.ICANON & ~termios.ECHO
- settings[6][termios.VMIN] = 1
- settings[6][termios.VTIME] = 0
- termios.tcsetattr(self.fd, termios.TCSANOW, settings)
-
- def unconfigure(self):
- termios.tcsetattr(self.fd, termios.TCSAFLUSH, self.default_settings)
-
- def getkey(self):
- return os.read(self.fd, 1)
-
-
-sfl_prompt_req = b"F7: boot from serial\n"
-sfl_prompt_ack = b"\x06"
-
-sfl_magic_req = b"sL5DdSMmkekro\n"
-sfl_magic_ack = b"z6IHG7cYDID6o\n"
-
-# General commands
-sfl_cmd_abort = b"\x00"
-sfl_cmd_load = b"\x01"
-sfl_cmd_jump = b"\x02"
-
-# Replies
-sfl_ack_success = b"K"
-sfl_ack_crcerror = b"C"
-sfl_ack_unknown = b"U"
-sfl_ack_error = b"E"
-
-
-crc16_table = [
- 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7,
- 0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF,
- 0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6,
- 0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE,
- 0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485,
- 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D,
- 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4,
- 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC,
- 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
- 0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B,
- 0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12,
- 0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A,
- 0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41,
- 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49,
- 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70,
- 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78,
- 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F,
- 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
- 0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E,
- 0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256,
- 0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D,
- 0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
- 0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C,
- 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634,
- 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB,
- 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3,
- 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
- 0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92,
- 0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9,
- 0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1,
- 0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8,
- 0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0
-]
-
-
-def crc16(l):
- crc = 0
- for d in l:
- crc = crc16_table[((crc >> 8) ^ d) & 0xff] ^ (crc << 8)
- return crc & 0xffff
-
-
-class SFLFrame:
- def __init__(self):
- self.cmd = bytes()
- self.payload = bytes()
-
- def compute_crc(self):
- return crc16(self.cmd + self.payload)
-
- def encode(self):
- packet = bytes([len(self.payload)])
- packet += self.compute_crc().to_bytes(2, "big")
- packet += self.cmd
- packet += self.payload
- return packet
-
-
-class LiteXTerm:
- def __init__(self, serial_boot, kernel_image, kernel_address):
- self.serial_boot = serial_boot
- self.kernel_image = kernel_image
- self.kernel_address = kernel_address
-
- self.reader_alive = False
- self.writer_alive = False
-
- self.prompt_detect_buffer = bytes(len(sfl_prompt_req))
- self.magic_detect_buffer = bytes(len(sfl_magic_req))
-
- self.console = Console()
-
- def open(self, port, baudrate):
- if hasattr(self, "port"):
- return
- self.port = serial.serial_for_url(port, baudrate)
-
- def close(self):
- if not hasattr(self, "port"):
- return
- self.port.close()
- del self.port
-
- def send_frame(self, frame):
- retry = 1
- while retry:
- self.port.write(frame.encode())
- # Get the reply from the device
- reply = self.port.read()
- if reply == sfl_ack_success:
- retry = 0
- elif reply == sfl_ack_crcerror:
- retry = 1
- else:
- print("[TERM] Got unknown reply '{}' from the device, aborting.".format(reply))
- return 0
- return 1
-
- def upload(self, filename, address):
- with open(filename, "rb") as f:
- data = f.read()
- print("[TERM] Uploading {} ({} bytes)...".format(filename, len(data)))
- current_address = address
- position = 0
- length = len(data)
- start = time.time()
- while len(data):
- sys.stdout.write("|{}>{}| {}%\r".format('=' * (20*position//length),
- ' ' * (20-20*position//length),
- 100*position//length))
- sys.stdout.flush()
- frame = SFLFrame()
- frame_data = data[:251]
- frame.cmd = sfl_cmd_load
- frame.payload = current_address.to_bytes(4, "big")
- frame.payload += frame_data
- if self.send_frame(frame) == 0:
- return
- current_address += len(frame_data)
- position += len(frame_data)
- try:
- data = data[251:]
- except:
- data = []
- end = time.time()
- elapsed = end - start
- print("[TERM] Upload complete ({0:.1f}KB/s).".format(length/(elapsed*1024)))
- return length
-
- def boot(self):
- print("[TERM] Booting the device.")
- frame = SFLFrame()
- frame.cmd = sfl_cmd_jump
- frame.payload = self.kernel_address.to_bytes(4, "big")
- self.send_frame(frame)
-
- def detect_prompt(self, data):
- if len(data):
- self.prompt_detect_buffer = self.prompt_detect_buffer[1:] + data
- return self.prompt_detect_buffer == sfl_prompt_req
- else:
- return False
-
- def answer_prompt(self):
- print("[TERM] Received serial boot prompt from the device.")
- self.port.write(sfl_prompt_ack)
-
- def detect_magic(self, data):
- if len(data):
- self.magic_detect_buffer = self.magic_detect_buffer[1:] + data
- return self.magic_detect_buffer == sfl_magic_req
- else:
- return False
-
- def answer_magic(self):
- print("[TERM] Received firmware download request from the device.")
- if os.path.exists(self.kernel_image):
- self.port.write(sfl_magic_ack)
- self.upload(self.kernel_image, self.kernel_address)
- self.boot()
- print("[TERM] Done.");
-
- def reader(self):
- try:
- while self.reader_alive:
- c = self.port.read()
- if c == b"\r":
- sys.stdout.buffer.write(b"\n")
- else:
- sys.stdout.buffer.write(c)
- sys.stdout.flush()
-
- if self.kernel_image is not None:
- if self.serial_boot and self.detect_prompt(c):
- self.answer_prompt()
- if self.detect_magic(c):
- self.answer_magic()
-
- except serial.SerialException:
- self.reader_alive = False
- raise
-
- def start_reader(self):
- self.reader_alive = True
- self.reader_thread = threading.Thread(target=self.reader)
- self.reader_thread.setDaemon(True)
- self.reader_thread.start()
-
- def stop_reader(self):
- self.reader_alive = False
- self.reader_thread.join()
-
- def writer(self):
- try:
- while self.writer_alive:
- b = self.console.getkey()
- if b == b"\x03":
- self.stop()
- elif b == b"\n":
- self.port.write(b"\x0a")
- else:
- self.port.write(b)
- except:
- self.writer_alive = False
- raise
-
- def start_writer(self):
- self.writer_alive = True
- self.writer_thread = threading.Thread(target=self.writer)
- self.writer_thread.setDaemon(True)
- self.writer_thread.start()
-
- def stop_writer(self):
- self.writer_alive = False
- self.writer_thread.join()
-
- def start(self):
- print("[TERM] Starting....")
- self.start_reader()
- self.start_writer()
-
- def stop(self):
- self.reader_alive = False
- self.writer_alive = False
-
- def join(self, writer_only=False):
- self.writer_thread.join()
- if not writer_only:
- self.reader_thread.join()
-
-
-def _get_args():
- parser = argparse.ArgumentParser()
- parser.add_argument("port", help="serial port")
- parser.add_argument("--speed", default=115200, help="serial baudrate")
- parser.add_argument("--serial-boot", default=False, action='store_true',
- help="automatically initiate serial boot")
- parser.add_argument("--kernel", default=None, help="kernel image")
- parser.add_argument("--kernel-adr", type=lambda a: int(a, 0), default=0x40000000, help="kernel address")
- return parser.parse_args()
-
-
-def main():
- args = _get_args()
- term = LiteXTerm(args.serial_boot, args.kernel, args.kernel_adr)
- term.console.configure()
- try:
- term.open(args.port, args.speed)
- term.start()
- term.join(True)
- except KeyboardInterrupt:
- term.console.unconfigure()
- finally:
- term.console.unconfigure()
- term.close()
-
-if __name__ == "__main__":
- main()
include_package_data=True,
entry_points={
"console_scripts": [
- "mkmscimg=litex.soc.tools.mkmscimg:main",
- "litex_term=litex.utils.litex_term:main",
- "litex_server=litex.utils.litex_server:main",
- "litex_sim=litex.utils.litex_sim:main",
- "litex_read_verilog=litex.utils.litex_read_verilog:main",
+ "litex_term=litex.tools.litex_term:main",
+ "litex_server=litex.tools.litex_server:main",
+ "litex_sim=litex.tools.litex_sim:main",
+ "litex_read_verilog=litex.tools.litex_read_verilog:main",
"litex_simple=litex.boards.targets.simple:main",
],
},