import datetime
from litex.soc.interconnect.csr import _CompoundCSR
+from litex.soc.integration import export
from .csr import DocumentedCSRRegion
from .module import gather_submodules, ModuleNotDocumented, DocumentedModule, DocumentedInterrupts
from .rst import reflow
html_static_path = ['_static']
"""
-
-def sub_csr_bit_range(busword, csr, offset):
- nwords = (csr.size + busword - 1)//busword
- i = nwords - offset - 1
- nbits = min(csr.size - i*busword, busword) - 1
- name = (csr.name + str(i) if nwords > 1 else csr.name).upper()
- origin = i*busword
- return (origin, nbits, name)
-
-
-def print_svd_register(csr, csr_address, description, length, svd):
- print(' <register>', file=svd)
- print(' <name>{}</name>'.format(csr.short_numbered_name), file=svd)
- if description is not None:
- print(
- ' <description><![CDATA[{}]]></description>'.format(description), file=svd)
- print(
- ' <addressOffset>0x{:04x}</addressOffset>'.format(csr_address), file=svd)
- print(
- ' <resetValue>0x{:02x}</resetValue>'.format(csr.reset_value), file=svd)
- print(' <size>{}</size>'.format(length), file=svd)
- print(' <access>{}</access>'.format(csr.access), file=svd)
- csr_address = csr_address + 4
- print(' <fields>', file=svd)
- if hasattr(csr, "fields") and len(csr.fields) > 0:
- for field in csr.fields:
- print(' <field>', file=svd)
- print(
- ' <name>{}</name>'.format(field.name), file=svd)
- print(' <msb>{}</msb>'.format(field.offset +
- field.size - 1), file=svd)
- print(' <bitRange>[{}:{}]</bitRange>'.format(
- field.offset + field.size - 1, field.offset), file=svd)
- print(
- ' <lsb>{}</lsb>'.format(field.offset), file=svd)
- print(' <description><![CDATA[{}]]></description>'.format(
- reflow(field.description)), file=svd)
- print(' </field>', file=svd)
- else:
- field_size = csr.size
- field_name = csr.short_name.lower()
- # Strip off "ev_" from eventmanager fields
- if field_name == "ev_enable":
- field_name = "enable"
- elif field_name == "ev_pending":
- field_name = "pending"
- elif field_name == "ev_status":
- field_name = "status"
- print(' <field>', file=svd)
- print(' <name>{}</name>'.format(field_name), file=svd)
- print(' <msb>{}</msb>'.format(field_size - 1), file=svd)
- print(
- ' <bitRange>[{}:{}]</bitRange>'.format(field_size - 1, 0), file=svd)
- print(' <lsb>{}</lsb>'.format(0), file=svd)
- print(' </field>', file=svd)
- print(' </fields>', file=svd)
- print(' </register>', file=svd)
-
-
-def generate_svd(soc, buildpath, vendor="litex", name="soc", filename=None, description=None):
- interrupts = {}
- for csr, irq in sorted(soc.soc_interrupt_map.items()):
- interrupts[csr] = irq
-
- documented_regions = []
-
- raw_regions = []
- if hasattr(soc, "get_csr_regions"):
- raw_regions = soc.get_csr_regions()
- else:
- for region_name, region in soc.csr_regions.items():
- raw_regions.append((region_name, region.origin,
- region.busword, region.obj))
- for csr_region in raw_regions:
- documented_regions.append(DocumentedCSRRegion(
- csr_region, csr_data_width=soc.csr_data_width))
-
+def generate_svd(soc, buildpath, filename=None, name="soc", **kwargs):
if filename is None:
filename = name + ".svd"
+ kwargs["name"] = name
with open(buildpath + "/" + filename, "w", encoding="utf-8") as svd:
- print('<?xml version="1.0" encoding="utf-8"?>', file=svd)
- print('', file=svd)
- print('<device schemaVersion="1.1" xmlns:xs="http://www.w3.org/2001/XMLSchema-instance" xs:noNamespaceSchemaLocation="CMSIS-SVD.xsd" >', file=svd)
- print(' <vendor>{}</vendor>'.format(vendor), file=svd)
- print(' <name>{}</name>'.format(name.upper()), file=svd)
- if description is not None:
- print(
- ' <description><![CDATA[{}]]></description>'.format(reflow(description)), file=svd)
- print('', file=svd)
- print(' <addressUnitBits>8</addressUnitBits>', file=svd)
- print(' <width>32</width>', file=svd)
- print(' <size>32</size>', file=svd)
- print(' <access>read-write</access>', file=svd)
- print(' <resetValue>0x00000000</resetValue>', file=svd)
- print(' <resetMask>0xFFFFFFFF</resetMask>', file=svd)
- print('', file=svd)
- print(' <peripherals>', file=svd)
-
- for region in documented_regions:
- csr_address = 0
- print(' <peripheral>', file=svd)
- print(' <name>{}</name>'.format(region.name.upper()), file=svd)
- print(
- ' <baseAddress>0x{:08X}</baseAddress>'.format(region.origin), file=svd)
- print(
- ' <groupName>{}</groupName>'.format(region.name.upper()), file=svd)
- if len(region.sections) > 0:
- print(' <description><![CDATA[{}]]></description>'.format(
- reflow(region.sections[0].body())), file=svd)
- print(' <registers>', file=svd)
- for csr in region.csrs:
- description = None
- if hasattr(csr, "description"):
- description = csr.description
- if isinstance(csr, _CompoundCSR) and len(csr.simple_csrs) > 1:
- is_first = True
- for i in range(len(csr.simple_csrs)):
- (start, length, name) = sub_csr_bit_range(
- region.busword, csr, i)
- if length > 0:
- bits_str = "Bits {}-{} of `{}`.".format(
- start, start+length, csr.name)
- else:
- bits_str = "Bit {} of `{}`.".format(
- start, csr.name)
- if is_first:
- if description is not None:
- print_svd_register(
- csr.simple_csrs[i], csr_address, bits_str + " " + description, length, svd)
- else:
- print_svd_register(
- csr.simple_csrs[i], csr_address, bits_str, length, svd)
- is_first = False
- else:
- print_svd_register(
- csr.simple_csrs[i], csr_address, bits_str, length, svd)
- csr_address = csr_address + 4
- else:
- length = ((csr.size + region.busword - 1) //
- region.busword) * region.busword
- print_svd_register(
- csr, csr_address, description, length, svd)
- csr_address = csr_address + 4
- print(' </registers>', file=svd)
- print(' <addressBlock>', file=svd)
- print(' <offset>0</offset>', file=svd)
- print(
- ' <size>0x{:x}</size>'.format(csr_address), file=svd)
- print(' <usage>registers</usage>', file=svd)
- print(' </addressBlock>', file=svd)
- if region.name in interrupts:
- print(' <interrupt>', file=svd)
- print(' <name>{}</name>'.format(region.name), file=svd)
- print(
- ' <value>{}</value>'.format(interrupts[region.name]), file=svd)
- print(' </interrupt>', file=svd)
- print(' </peripheral>', file=svd)
- print(' </peripherals>', file=svd)
- print('</device>', file=svd)
+ svd.write(export.get_svd(soc, **kwargs))
def generate_docs(soc, base_dir, project_name="LiteX SoC Project",
if len(additional_modules) > 0:
print("""
Modules
--------
+=======
.. toctree::
:maxdepth: 1
if len(documented_regions) > 0:
print("""
Register Groups
----------------
+===============
.. toctree::
:maxdepth: 1
print("""
Indices and tables
-------------------
+==================
* :ref:`genindex`
* :ref:`modindex`
from litex.build.tools import generated_banner
+from litex.soc.doc.rst import reflow
+from litex.soc.doc.module import gather_submodules, ModuleNotDocumented, DocumentedModule, DocumentedInterrupts
+from litex.soc.doc.csr import DocumentedCSRRegion
+from litex.soc.interconnect.csr import _CompoundCSR
+
# CPU files ----------------------------------------------------------------------------------------
def get_cpu_mak(cpu, compile_software):
d["memories"][name]["type"],
)
return r
+
+# SVD Export --------------------------------------------------------------------------------------
+
+def get_svd(soc, vendor="litex", name="soc", description=None):
+ def sub_csr_bit_range(busword, csr, offset):
+ nwords = (csr.size + busword - 1)//busword
+ i = nwords - offset - 1
+ nbits = min(csr.size - i*busword, busword) - 1
+ name = (csr.name + str(i) if nwords > 1 else csr.name).upper()
+ origin = i*busword
+ return (origin, nbits, name)
+
+ def print_svd_register(csr, csr_address, description, length, svd):
+ svd.append(' <register>')
+ svd.append(' <name>{}</name>'.format(csr.short_numbered_name))
+ if description is not None:
+ svd.append(' <description><![CDATA[{}]]></description>'.format(description))
+ svd.append(' <addressOffset>0x{:04x}</addressOffset>'.format(csr_address))
+ svd.append(' <resetValue>0x{:02x}</resetValue>'.format(csr.reset_value))
+ svd.append(' <size>{}</size>'.format(length))
+ svd.append(' <access>{}</access>'.format(csr.access))
+ csr_address = csr_address + 4
+ svd.append(' <fields>')
+ if hasattr(csr, "fields") and len(csr.fields) > 0:
+ for field in csr.fields:
+ svd.append(' <field>')
+ svd.append(' <name>{}</name>'.format(field.name))
+ svd.append(' <msb>{}</msb>'.format(field.offset +
+ field.size - 1))
+ svd.append(' <bitRange>[{}:{}]</bitRange>'.format(
+ field.offset + field.size - 1, field.offset))
+ svd.append(' <lsb>{}</lsb>'.format(field.offset))
+ svd.append(' <description><![CDATA[{}]]></description>'.format(
+ reflow(field.description)))
+ svd.append(' </field>')
+ else:
+ field_size = csr.size
+ field_name = csr.short_name.lower()
+ # Strip off "ev_" from eventmanager fields
+ if field_name == "ev_enable":
+ field_name = "enable"
+ elif field_name == "ev_pending":
+ field_name = "pending"
+ elif field_name == "ev_status":
+ field_name = "status"
+ svd.append(' <field>')
+ svd.append(' <name>{}</name>'.format(field_name))
+ svd.append(' <msb>{}</msb>'.format(field_size - 1))
+ svd.append(' <bitRange>[{}:{}]</bitRange>'.format(field_size - 1, 0))
+ svd.append(' <lsb>{}</lsb>'.format(0))
+ svd.append(' </field>')
+ svd.append(' </fields>')
+ svd.append(' </register>')
+
+ interrupts = {}
+ for csr, irq in sorted(soc.soc_interrupt_map.items()):
+ interrupts[csr] = irq
+
+ documented_regions = []
+
+ raw_regions = []
+ if hasattr(soc, "get_csr_regions"):
+ raw_regions = soc.get_csr_regions()
+ else:
+ for region_name, region in soc.csr_regions.items():
+ raw_regions.append((region_name, region.origin,
+ region.busword, region.obj))
+ for csr_region in raw_regions:
+ documented_regions.append(DocumentedCSRRegion(
+ csr_region, csr_data_width=soc.csr_data_width))
+
+ svd = []
+ svd.append('<?xml version="1.0" encoding="utf-8"?>')
+ svd.append('')
+ svd.append('<device schemaVersion="1.1" xmlns:xs="http://www.w3.org/2001/XMLSchema-instance" xs:noNamespaceSchemaLocation="CMSIS-SVD.xsd" >')
+ svd.append(' <vendor>{}</vendor>'.format(vendor))
+ svd.append(' <name>{}</name>'.format(name.upper()))
+ if description is not None:
+ svd.append(' <description><![CDATA[{}]]></description>'.format(reflow(description)))
+ svd.append('')
+ svd.append(' <addressUnitBits>8</addressUnitBits>')
+ svd.append(' <width>32</width>')
+ svd.append(' <size>32</size>')
+ svd.append(' <access>read-write</access>')
+ svd.append(' <resetValue>0x00000000</resetValue>')
+ svd.append(' <resetMask>0xFFFFFFFF</resetMask>')
+ svd.append('')
+ svd.append(' <peripherals>')
+
+ for region in documented_regions:
+ csr_address = 0
+ svd.append(' <peripheral>')
+ svd.append(' <name>{}</name>'.format(region.name.upper()))
+ svd.append(' <baseAddress>0x{:08X}</baseAddress>'.format(region.origin))
+ svd.append(' <groupName>{}</groupName>'.format(region.name.upper()))
+ if len(region.sections) > 0:
+ svd.append(' <description><![CDATA[{}]]></description>'.format(
+ reflow(region.sections[0].body())))
+ svd.append(' <registers>')
+ for csr in region.csrs:
+ description = None
+ if hasattr(csr, "description"):
+ description = csr.description
+ if isinstance(csr, _CompoundCSR) and len(csr.simple_csrs) > 1:
+ is_first = True
+ for i in range(len(csr.simple_csrs)):
+ (start, length, name) = sub_csr_bit_range(
+ region.busword, csr, i)
+ if length > 0:
+ bits_str = "Bits {}-{} of `{}`.".format(
+ start, start+length, csr.name)
+ else:
+ bits_str = "Bit {} of `{}`.".format(
+ start, csr.name)
+ if is_first:
+ if description is not None:
+ print_svd_register(
+ csr.simple_csrs[i], csr_address, bits_str + " " + description, length, svd)
+ else:
+ print_svd_register(
+ csr.simple_csrs[i], csr_address, bits_str, length, svd)
+ is_first = False
+ else:
+ print_svd_register(
+ csr.simple_csrs[i], csr_address, bits_str, length, svd)
+ csr_address = csr_address + 4
+ else:
+ length = ((csr.size + region.busword - 1) //
+ region.busword) * region.busword
+ print_svd_register(
+ csr, csr_address, description, length, svd)
+ csr_address = csr_address + 4
+ svd.append(' </registers>')
+ svd.append(' <addressBlock>')
+ svd.append(' <offset>0</offset>')
+ svd.append(' <size>0x{:x}</size>'.format(csr_address))
+ svd.append(' <usage>registers</usage>')
+ svd.append(' </addressBlock>')
+ if region.name in interrupts:
+ svd.append(' <interrupt>')
+ svd.append(' <name>{}</name>'.format(region.name))
+ svd.append(' <value>{}</value>'.format(interrupts[region.name]))
+ svd.append(' </interrupt>')
+ svd.append(' </peripheral>')
+ svd.append(' </peripherals>')
+ svd.append('</device>')
+ return "\n".join(svd)