def get_csr_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.irq.locs.items()): interrupts[csr] = irq documented_regions = [] for name, region in soc.csr.regions.items(): documented_regions.append(DocumentedCSRRegion( name = name, region = 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>') if len(soc.mem_regions) > 0: svd.append(' <vendorExtensions>') svd.append(' <memoryRegions>') for name, region in soc.mem_regions.items(): svd.append(' <memoryRegion>') svd.append(' <name>{}</name>'.format(name.upper())) svd.append(' <baseAddress>0x{:08X}</baseAddress>'.format(region.origin)) svd.append(' <size>0x{:08X}</size>'.format(region.size)) svd.append(' </memoryRegion>') svd.append(' </memoryRegions>') svd.append(' </vendorExtensions>') svd.append('</device>') return "\n".join(svd)
def get_csr_svd(jinja_env, soc, vendor="litex", name="soc", description=None): interrupts = {} for csr, irq in sorted(soc.irq.locs.items()): interrupts[csr] = irq documented_regions = [] for region_name, region in soc.csr.regions.items(): documented_regions.append(DocumentedCSRRegion( name = region_name, region = 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))) else: fmt = "%Y-%m-%d %H:%M:%S" build_time = datetime.datetime.fromtimestamp(time.time()).strftime(fmt) svd.append(' <description><![CDATA[{}]]></description>'.format(reflow("Litex SoC " + build_time))) 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(' <vendorExtensions>') if len(soc.mem_regions) > 0: svd.append(' <memoryRegions>') for region_name, region in soc.mem_regions.items(): svd.append(' <memoryRegion>') svd.append(' <name>{}</name>'.format(region_name.upper())) svd.append(' <baseAddress>0x{:08X}</baseAddress>'.format(region.origin)) svd.append(' <size>0x{:08X}</size>'.format(region.size)) svd.append(' </memoryRegion>') svd.append(' </memoryRegions>') svd.append(' <constants>') for name, value in soc.constants.items(): svd.append(' <constant name="{}" value="{}" />'.format(name, value)) svd.append(' </constants>') svd.append(' </vendorExtensions>') svd.append('</device>') return "\n".join(svd)