mirror of
https://github.com/enjoy-digital/litex.git
synced 2025-01-04 09:52:26 -05:00
137 lines
5.1 KiB
Python
137 lines
5.1 KiB
Python
#
|
|
# This file is part of LiteX.
|
|
#
|
|
# Copyright (c) 2015-2020 Florent Kermarrec <florent@enjoy-digital.fr>
|
|
# Copyright (c) 2016 Tim 'mithro' Ansell <mithro@mithis.com>
|
|
# SPDX-License-Identifier: BSD-2-Clause
|
|
|
|
import csv
|
|
|
|
# CSR Elements -------------------------------------------------------------------------------------
|
|
|
|
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, type):
|
|
self.base = base
|
|
self.size = size
|
|
self.type = type
|
|
|
|
# CSR Builder --------------------------------------------------------------------------------------
|
|
|
|
class CSRBuilder:
|
|
def __init__(self, comm, csr_csv, csr_data_width=None, csr_bus_address_width=None):
|
|
if csr_csv is not None:
|
|
self.items = self.get_csr_items(csr_csv)
|
|
self.constants = self.build_constants()
|
|
|
|
# Load csr_data_width from the constants, otherwise it must be provided
|
|
constant_csr_data_width = self.constants.d.get("config_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))
|
|
|
|
# Load csr_data_width from the constants, otherwise it must be provided
|
|
constant_csr_bus_address_width = self.constants.d.get("config_bus_address_width", None)
|
|
if csr_bus_address_width is None:
|
|
csr_bus_address_width = constant_csr_bus_address_width
|
|
if csr_bus_address_width is None:
|
|
raise KeyError("csr_bus_address_width not found in constants, please provide!")
|
|
if csr_bus_address_width != constant_csr_bus_address_width:
|
|
raise KeyError("csr_bus_address_width of {} provided but {} found in constants".format(
|
|
csr_bus_address_width, constant_csr_bus_address_width))
|
|
|
|
self.csr_data_width = csr_data_width
|
|
self.csr_bus_address_width = csr_bus_address_width
|
|
self.bases = self.build_bases()
|
|
self.regs = self.build_registers(comm.read, comm.write)
|
|
self.mems = self.build_memories()
|
|
|
|
@staticmethod
|
|
def get_csr_items(csr_csv):
|
|
return list(csv.reader(filter(lambda row: row[0] != "#", open(csr_csv))))
|
|
|
|
def build_bases(self):
|
|
d = {}
|
|
for item in self.items:
|
|
group, name, addr, dummy0, dummy1 = item
|
|
if group == "csr_base":
|
|
d[name] = int(addr.replace("0x", ""), 16)
|
|
return CSRElements(d)
|
|
|
|
def build_registers(self, readfn, writefn):
|
|
d = {}
|
|
for item in self.items:
|
|
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):
|
|
d = {}
|
|
for item in self.items:
|
|
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):
|
|
d = {}
|
|
for item in self.items:
|
|
group, name, base, size, type = item
|
|
if group == "memory_region":
|
|
d[name] = CSRMemoryRegion(int(base, 16), int(size), type)
|
|
return CSRElements(d)
|