614 lines
18 KiB
Python
Executable File
614 lines
18 KiB
Python
Executable File
#!/usr/bin/python
|
|
# pylint: disable=line-too-long, C0325, missing-docstring
|
|
import os
|
|
import re
|
|
import json
|
|
import argparse
|
|
import fnmatch
|
|
import logging
|
|
from collections import Counter
|
|
|
|
|
|
logging.basicConfig(level=logging.INFO)
|
|
|
|
|
|
# parameters
|
|
URI_PREFIX = "https://github.com/renode/renode/tree/master/"
|
|
PERIPHERALS_URI_PREFIX = "https://github.com/renode/renode-infrastructure/tree/master/"
|
|
PERIPHERAL_LINE_PATTERN = r'^[A-Za-z0-9_]+\s*:\s*([^\s]+)\s*@'
|
|
USING_LINE_PATTERN = r'^using "([.A-Za-z0-9_/-]+)"'
|
|
TOP_DIR = None
|
|
|
|
GROUPS = []
|
|
PLATFORMS = []
|
|
PERIPHERALS = []
|
|
CATEGORIES = []
|
|
|
|
|
|
def get_or_create_platform(path):
|
|
for p in PLATFORMS:
|
|
if p._path == path:
|
|
return p
|
|
|
|
p = Platform(path)
|
|
PLATFORMS.append(p)
|
|
|
|
return p
|
|
|
|
|
|
def get_or_create_peripheral(kind_name, class_name):
|
|
p = Peripheral(kind_name, class_name)
|
|
return p
|
|
|
|
|
|
def try_get_category(platform):
|
|
mapping = {
|
|
"A2_CV32E40P": "OHG",
|
|
"a20": "ALLWINNER",
|
|
"ambiq-apollo4": "AMBIQ",
|
|
"arduino_101-shield": "NRF",
|
|
"arduino_nano_33_ble": "NRF",
|
|
"arty_litex_vexriscv": "LITEX",
|
|
"arvsom": "STARFIVE",
|
|
"at91rm9200": "MICROCHIP",
|
|
"atsamd21j17d-aft": "MICROCHIP",
|
|
"atsamd51g19a": "MICROCHIP",
|
|
"beaglev-fire": "PFSOC",
|
|
"beaglev_starlight": "STARFIVE",
|
|
"brd4116a": "EFM",
|
|
"brd4117a": "EFM",
|
|
"brd4118a": "EFM",
|
|
"brd4120a": "EFM",
|
|
"brd4121a": "EFM",
|
|
"brd4162a": "EFM",
|
|
"brd4186c": "EFM",
|
|
"brd4402a": "EFM",
|
|
"cc2538": "TI",
|
|
"colibri-vf61": "NXP I.MX",
|
|
"core-v-mcu": "OHG",
|
|
"cortex-a53": "GENERIC ARM",
|
|
"cortex-a53-gicv2": "GENERIC ARM",
|
|
"cortex-a53-gicv3": "GENERIC ARM",
|
|
"cortex-a53-gicv3_smp": "GENERIC ARM",
|
|
"cortex_a53_virtio": "GENERIC ARM",
|
|
"cortex_a53_console": "GENERIC ARM",
|
|
"cortex-a78": "GENERIC ARM",
|
|
"cortex-r52": "GENERIC ARM",
|
|
"cortex-r52_smp": "GENERIC ARM",
|
|
"cortex-r52_smp_4": "GENERIC ARM",
|
|
"cortex-r8": "GENERIC ARM",
|
|
"crosslink-nx-evn": "LITEX",
|
|
"efm32g210": "EFM",
|
|
"efm32g222": "EFM",
|
|
"efm32g232": "EFM",
|
|
"efm32g842": "EFM",
|
|
"efm32g890": "EFM",
|
|
"efm32gg942": "EFM",
|
|
"efm32gg995": "EFM",
|
|
"efm32hg350": "EFM",
|
|
"efm32jg1": "EFM",
|
|
"efm32jg12": "EFM",
|
|
"efm32lg942": "EFM",
|
|
"efm32lg995": "EFM",
|
|
"efm32pg1": "EFM",
|
|
"efm32pg12": "EFM",
|
|
"efm32tg840": "EFM",
|
|
"efm32wg995": "EFM",
|
|
"efm32zg222": "EFM",
|
|
"efr32mg1": "EFM",
|
|
"efr32mg12": "EFM",
|
|
"efr32mg13": "EFM",
|
|
"efr32mg24": "EFM",
|
|
"efr32mg26": "EFM",
|
|
"efr32xg22": "EFM",
|
|
"egis_et171": "EGIS",
|
|
"focaltech_ft9001": "FOCALTECH",
|
|
"eos-s3": "EOS",
|
|
"eos-s3-qomu": "EOS",
|
|
"eos-s3-quickfeather": "EOS",
|
|
"ezr32hg320": "EFM",
|
|
"ezr32lg330": "EFM",
|
|
"ezr32wg330": "EMF",
|
|
"fomu": "LITEX",
|
|
"fsl_lx2160ardb": "NXP LAYERSCAPE",
|
|
"gr716": "GAISLER",
|
|
"gr716-devboard": "GAISLER",
|
|
"gr712rc": "GAISLER",
|
|
"x86": "X86",
|
|
"ice40up5k-mdp-evn": "LITEX",
|
|
"imxrt1064": "NXP I.MX",
|
|
"imxrt500": "NXP I.MX",
|
|
"mimxrt798s": "NXP I.MX",
|
|
"mimxrt700_evk": "NXP I.MX",
|
|
"kendryte_k210": "KENDRYTE",
|
|
"leon3": "GAISLER",
|
|
"leon3-externals": "GAISLER",
|
|
"litex_common": "LITEX",
|
|
"litex_ibex": "LITEX",
|
|
"litex_linux_vexriscv_sdcard": "LITEX",
|
|
"litex_microwatt": "LITEX",
|
|
"litex_minerva": "LITEX",
|
|
"litex_nexys_video_vexriscv_linux": "LITEX",
|
|
"litex_picorv32": "LITEX",
|
|
"litex_tock": "LITEX",
|
|
"litex_vexriscv": "LITEX",
|
|
"litex_vexriscv_linux": "LITEX",
|
|
"litex_vexriscv_micropython": "LITEX",
|
|
"litex_vexriscv_smp": "LITEX",
|
|
"litex_vexriscv_tftp": "LITEX",
|
|
"litex_vexriscv_verilated_cfu": "LITEX",
|
|
"litex_vexriscv_verilated_liteuart": "LITEX",
|
|
"litex_vexriscv_zephyr": "LITEX",
|
|
"litex_zephyr_vexriscv_i2s": "LITEX",
|
|
"lpc2294": "NXP LPC",
|
|
"mars_zx3": "ZYNQ",
|
|
"mars_zx3-externals": "ZYNQ",
|
|
"max32652": "MAXIM",
|
|
"max32652-evkit": "MAXIM",
|
|
"microwatt": "POWERPC",
|
|
"mimxrt1064_evk": "NXP I.MX",
|
|
"miv": "MIV",
|
|
"miv_rv32": "MIV",
|
|
"miv-board": "MIV",
|
|
"miv-board-additional-uarts": "MIV",
|
|
"mpc5567": "NXP PPC",
|
|
"mpfs-icicle-kit": "PFSOC",
|
|
"msp430f2619": "MSP430",
|
|
"murax_vexriscv": "OTHER RISC-V",
|
|
"murax_vexriscv_verilated_uart": "OTHER RISC-V",
|
|
"nrf52840": "NORDIC",
|
|
"nrf52840dk_nrf52840": "NORDIC",
|
|
"nucleo_wba52cg": "STM",
|
|
"nucleo_h753zi": "STM",
|
|
"nxp-k6xf": "NXP KINETIS",
|
|
"opentitan-earlgrey": "OTHER RISC-V",
|
|
"opentitan-earlgrey-cw310": "OTHER RISC-V",
|
|
"picosoc": "OTHER RISC-V",
|
|
"polarfire-soc": "PFSOC",
|
|
"quark-c1000": "X86",
|
|
"quark_c1000-cc2520": "X86",
|
|
"acrn_x86_64": "X86-64",
|
|
"up_squared_x86_64": "X86-64",
|
|
"renesas_rz_t2m": "RENESAS",
|
|
"renesas_rz_t2m_rsk": "RENESAS",
|
|
"renesas_rz_g2l": "RENESAS",
|
|
"ri5cy": "OTHER RISC-V",
|
|
"riscv_verilated_uartlite": "OTHER RISC-V",
|
|
"riscv_virt": "OTHER RISC-V",
|
|
"s32k118": "NXP S32K",
|
|
"nxp-s32k388": "NXP S32K",
|
|
"sam_e70": "MICROCHIP",
|
|
"sam4s": "MICROCHIP",
|
|
"sam4s8b": "MICROCHIP",
|
|
"sam4s16c": "MICROCHIP",
|
|
"sam4s_xplained": "MICROCHIP",
|
|
"sifive-fe310": "SIFIVE",
|
|
"sifive-fu540": "SIFIVE",
|
|
"sifive-fu740": "SIFIVE",
|
|
"sltb001a": "EFM",
|
|
"sltb004a": "EFM",
|
|
"slwstk6220a": "EFM",
|
|
"starfive-jh7100": "STARFIVE",
|
|
"stk3200": "EFM",
|
|
"stk3600": "EFM",
|
|
"stk3700": "EFM",
|
|
"stk3800": "EFM",
|
|
"stm32f0": "STM",
|
|
"stm32f042": "STM",
|
|
"stm32f072": "STM",
|
|
"stm32f072b_discovery": "STM",
|
|
"stm32f103": "STM",
|
|
"stm32f4": "STM",
|
|
"stm32f412": "STM",
|
|
"stm32f429": "STM",
|
|
"stm32f4_discovery": "STM",
|
|
"stm32f4_discovery-additional_gpios": "STM",
|
|
"stm32f4_discovery-bb": "STM",
|
|
"stm32f4_discovery-kit": "STM",
|
|
"stm32f746": "STM",
|
|
"stm32f7_discovery-bb": "STM",
|
|
"stm32g0": "STM",
|
|
"stm32h753": "STM",
|
|
"stm32h743": "STM",
|
|
"stm32l071": "STM",
|
|
"stm32l072": "STM",
|
|
"stm32l151": "STM",
|
|
"stm32l552": "STM",
|
|
"stm32w108": "STM",
|
|
"stm32wba52": "STM",
|
|
"tegra2": "TEGRA",
|
|
"tegra3": "TEGRA",
|
|
"tegra_externals": "TEGRA",
|
|
"tock_veer_el2_sim": "OTHER RISC-V",
|
|
"ut32m0r500": "GAISLER",
|
|
"verilated_ibex": "LITEX",
|
|
"versatile": "GENERIC ARM",
|
|
"vexpress": "GENERIC ARM",
|
|
"vexpress-externals": "GENERIC ARM",
|
|
"vybrid": "NXP I.MX",
|
|
"xtensa-sample-controller": "XTENSA",
|
|
"zedboard": "ZYNQ",
|
|
"zedboard-externals": "ZYNQ",
|
|
"zolertia-firefly": "ZYNQ",
|
|
"xilinx_zynqmp_r5": "ZYNQ",
|
|
"zynq-7000": "ZYNQ",
|
|
"zynqmp": "ZYNQ",
|
|
"zynqmp-zcu102-revA": "ZYNQ",
|
|
"zynqmp-zcu102-revB": "ZYNQ",
|
|
"zynqmp-zcu104": "ZYNQ",
|
|
"cortex-a9_smp": "GENERIC ARM",
|
|
"cortex-a9": "GENERIC ARM",
|
|
"cortex-r8_smp": "GENERIC ARM",
|
|
"cortex-r8": "GENERIC ARM",
|
|
"nuvoton_npcx9": "NUVOTON",
|
|
"nuvoton_npcx9m6fb_evb": "NUVOTON",
|
|
"andes_ae350_n25": "ANDES",
|
|
"renesas-r7fa8m1a": "RENESAS",
|
|
"renesas-r7fa2l1a": "RENESAS",
|
|
"renesas-r7fa2e1a9": "RENESAS",
|
|
"renesas-r7fa6m5b": "RENESAS",
|
|
"renesas-r7fa4m1a": "RENESAS",
|
|
"ck-ra6m5": "RENESAS",
|
|
"renesas-da14592": "RENESAS",
|
|
"ek-ra2e1": "RENESAS",
|
|
"ek-ra8m1": "RENESAS",
|
|
"arduino_uno_r4_minima": "RENESAS",
|
|
"renesas_ck_ra6m5_sensors_example": "RENESAS",
|
|
"renesas-ck_ra6m5": "RENESAS",
|
|
"renesas-ek_ra2e1": "RENESAS",
|
|
"renesas-ek_ra8m1": "RENESAS",
|
|
"renesas-rz_t2m_rsk": "RENESAS",
|
|
"vegaboard_ri5cy": "OTHER RISC-V",
|
|
"x86-kvm": "X86",
|
|
"x86_64-kvm": "X86-64",
|
|
"x86_64-kvm-virtio": "X86-64",
|
|
}
|
|
|
|
if platform.get_name() not in mapping:
|
|
raise Exception("don't know category for: {} ({})".format(platform.get_name(), platform._path))
|
|
|
|
result = mapping[platform.get_name()]
|
|
if result not in CATEGORIES:
|
|
CATEGORIES.append(result)
|
|
return result
|
|
|
|
|
|
class Platform:
|
|
def __init__(self, path):
|
|
self._path = path
|
|
self._peripherals = []
|
|
self._usings = []
|
|
self._cached_res = None
|
|
self._category = try_get_category(self)
|
|
|
|
self._parse()
|
|
|
|
def get_name(self):
|
|
return os.path.splitext(os.path.basename(self._path))[0]
|
|
|
|
def get_path(self):
|
|
return self._path
|
|
|
|
def get_peripherals(self):
|
|
if self._cached_res:
|
|
return self._cached_res
|
|
|
|
res = {}
|
|
|
|
for u in self._usings:
|
|
ps = u.get_peripherals()
|
|
for k in ps:
|
|
if k not in res:
|
|
res[k] = ps[k]
|
|
else:
|
|
res[k].extend(ps[k])
|
|
|
|
for p in self._peripherals:
|
|
if p._kind not in res:
|
|
res[p._kind] = [p._type]
|
|
else:
|
|
res[p._kind].append(p._type)
|
|
|
|
self._cached_res = res
|
|
return res
|
|
|
|
def get_all_peripherals(self):
|
|
# if self._cached_res:
|
|
# return self._cached_res
|
|
|
|
res = []
|
|
|
|
for u in self._usings:
|
|
ps = u.get_all_peripherals()
|
|
for k in ps:
|
|
found = False
|
|
for x in res:
|
|
if x == k:
|
|
x._count += 1
|
|
found = True
|
|
break
|
|
if not found:
|
|
res.append(k)
|
|
|
|
for k in self._peripherals:
|
|
found = False
|
|
for x in res:
|
|
if x == k:
|
|
x._count += 1
|
|
found = True
|
|
break
|
|
if not found:
|
|
res.append(k)
|
|
|
|
# self._cached_res = res
|
|
return res
|
|
|
|
def _parse(self):
|
|
with open(self._path, 'r') as f:
|
|
for line in f.readlines():
|
|
# maybe it's a using statement
|
|
m = re.search(USING_LINE_PATTERN, line)
|
|
if m:
|
|
match = m.group(1)
|
|
if match.startswith('.'):
|
|
path = os.path.join(os.path.dirname(self._path), match)
|
|
else:
|
|
path = os.path.join(TOP_DIR, match)
|
|
self._usings.append(get_or_create_platform(path))
|
|
continue
|
|
|
|
# maybe it's a peripheral definition
|
|
p = Peripheral.try_parse(line)
|
|
if p:
|
|
added = False
|
|
for xp in self._peripherals:
|
|
if xp == p:
|
|
xp._count += 1
|
|
added = True
|
|
break
|
|
|
|
if not added:
|
|
self._peripherals.append(p)
|
|
|
|
continue
|
|
|
|
def __str__(self):
|
|
res = "[PLATFORM: {}]".format(self._path)
|
|
for u in self._usings:
|
|
res += "\n [USING: {}]".format(u)
|
|
for p in self._peripherals:
|
|
res += "\n {}".format(p)
|
|
return res
|
|
|
|
|
|
class Peripheral:
|
|
def __init__(self, kind, type):
|
|
self._kind = kind
|
|
self._type = type
|
|
self._count = 1
|
|
|
|
path = find_file(TOP_DIR + '/src/Infrastructure', self._type + '.cs')
|
|
self._uri = '{}{}'.format(PERIPHERALS_URI_PREFIX, path)
|
|
|
|
@staticmethod
|
|
def try_parse(line):
|
|
m = re.search(PERIPHERAL_LINE_PATTERN, line)
|
|
if not m:
|
|
return None
|
|
|
|
type_name = m.group(1)
|
|
# put all peripherals without a namespace into 'Others'
|
|
if '.' not in type_name:
|
|
type_name = "Others." + type_name
|
|
|
|
kind_name, class_name = type_name.split('.', 1)
|
|
|
|
return get_or_create_peripheral(kind_name, class_name)
|
|
|
|
def __str__(self):
|
|
res = "[PERIPHERAL: {} / {}]".format(self._kind, self._type)
|
|
return res
|
|
|
|
def __hash__(self):
|
|
return hash(self._kind + self._type)
|
|
|
|
def __eq__(self, other):
|
|
return self._kind == other._kind and self._type == other._type
|
|
|
|
|
|
def find_file(root_folder, fname):
|
|
for _root, _, _filenames in os.walk(root_folder):
|
|
if fname in _filenames:
|
|
return os.path.join(_root[len(root_folder) + 1:], fname)
|
|
return None
|
|
|
|
|
|
|
|
def scan(folder):
|
|
# scan for json files
|
|
for root, dirnames, filenames in os.walk(folder):
|
|
for filename in fnmatch.filter(filenames, '*.repl'):
|
|
if 'fomu_led' in filename:
|
|
continue
|
|
platform = get_or_create_platform(os.path.join(root, filename))
|
|
|
|
for kind in platform.get_peripherals():
|
|
if kind not in GROUPS:
|
|
GROUPS.append(kind)
|
|
|
|
|
|
def generate_json():
|
|
return json.dumps(PLATFORMS, default=lambda x: {i:x.__dict__[i] for i in x.__dict__ if i != '_cached_res'}, indent=4, sort_keys=True)
|
|
|
|
|
|
def platform_to_html(platform):
|
|
res = ''
|
|
|
|
res += ' <h4 onclick="{1}">{0}</h4>\n'.format(platform.get_name(), "showPeripherals(this, '{}')".format(platform.get_name()))
|
|
|
|
return res
|
|
|
|
def platform_peripherals_table(platform):
|
|
res = ''
|
|
|
|
res += '<table class="boards-table docutils align-default" style="margin-top: 10px">\n'
|
|
res += '<tr>\n'
|
|
res += '<th>kind</td>\n'
|
|
res += '<th>type</td>\n'
|
|
res += '</tr>\n'
|
|
for peripheral in platform.get_all_peripherals():
|
|
res += '<tr>\n'
|
|
res += '<td>{}</td>\n'.format(peripheral._kind)
|
|
res += '<td><a href="{}">{}</a>{}</td>\n'.format(peripheral._uri, peripheral._type, ' (x{})'.format(peripheral._count) if peripheral._count > 1 else '')
|
|
res += '</tr>\n'
|
|
res += '</table>\n'
|
|
|
|
return res
|
|
|
|
def generate_html():
|
|
res = ''
|
|
|
|
res +="""
|
|
<style>
|
|
.category h3 {
|
|
background-color: #666;
|
|
border: none;
|
|
// color: #404040;
|
|
padding: 10px 20px;
|
|
text-align: center;
|
|
text-decoration: none;
|
|
display: inline-block;
|
|
margin: 4px 2px;
|
|
cursor: pointer;
|
|
border-radius: 16px;
|
|
}
|
|
|
|
.platform h4 {
|
|
background-color: white;
|
|
border: solid 1px;
|
|
border-color: #007ded;
|
|
color: #007ded;
|
|
padding: 10px 20px;
|
|
text-align: center;
|
|
text-decoration: none;
|
|
display: inline-block;
|
|
margin: 4px 2px;
|
|
cursor: pointer;
|
|
border-radius: 16px;
|
|
}
|
|
|
|
.platform_selected h4 {
|
|
background-color: #007ded;
|
|
border: solid 1px;
|
|
border-color: #007ded;
|
|
color: white;
|
|
padding: 10px 20px;
|
|
text-align: center;
|
|
text-decoration: none;
|
|
display: inline-block;
|
|
margin: 4px 2px;
|
|
cursor: pointer;
|
|
border-radius: 16px;
|
|
}
|
|
|
|
div.category {
|
|
display: inline-block;
|
|
}
|
|
|
|
div.platform {
|
|
display: none;
|
|
}
|
|
|
|
</style>
|
|
"""
|
|
|
|
PLATFORMS.sort(key=lambda x: x.get_name())
|
|
res += '<div style="margin-top: 10px; margin-bottom: 10px">\n'
|
|
for category in sorted(CATEGORIES):
|
|
res += '<div class="category">\n'.format(category)
|
|
res += ' <h3 onclick="toggleCategory(this)">{}</h3>\n'.format(category)
|
|
for platform in [x for x in PLATFORMS if x._category == category]:
|
|
res += ' <div class="platform">\n'.format(platform_to_html(platform))
|
|
res += platform_to_html(platform)
|
|
res += ' </div>\n'
|
|
res += '</div>\n'
|
|
res += '</div>\n'
|
|
|
|
for platform in PLATFORMS:
|
|
res += ' <div id="peripherals-{}" class="peripherals-table" style="display: none">\n'.format(platform.get_name())
|
|
res += platform_peripherals_table(platform)
|
|
res += ' </div>\n'
|
|
|
|
res +="""
|
|
<script>
|
|
|
|
function hideAllPeripherals () {
|
|
var kids = document.getElementsByClassName('peripherals-table');
|
|
for (kid of kids) {
|
|
kid.style.display = "none";
|
|
}
|
|
|
|
var kids = document.getElementsByClassName('platform_selected');
|
|
for (kid of kids) {
|
|
kid.className = "platform";
|
|
}
|
|
}
|
|
|
|
function showPeripherals (target, name) {
|
|
hideAllPeripherals();
|
|
|
|
target.parentElement.className = 'platform_selected';
|
|
|
|
var targetDiv = document.getElementById('peripherals-' + name);
|
|
targetDiv.style.display = '';
|
|
}
|
|
|
|
function toogleElementsByClass (element, className) {
|
|
var kids = element.getElementsByClassName(className);
|
|
for (kid of kids) {
|
|
if(kid.style.display == "none" || kid.style.display == "")
|
|
kid.style.display = "inline-block";
|
|
else
|
|
kid.style.display = "none";
|
|
}
|
|
}
|
|
|
|
function toggleCategory (element) {
|
|
hideAllPeripherals();
|
|
toogleElementsByClass(element.parentElement, "platform");
|
|
}
|
|
|
|
</script>
|
|
|
|
"""
|
|
|
|
return res
|
|
|
|
def main():
|
|
global TOP_DIR
|
|
|
|
parser = argparse.ArgumentParser()
|
|
|
|
parser.add_argument("-d", "--dir", dest="dir", action="store", default=".", help="Directory to scan")
|
|
parser.add_argument("-J", "--json", dest="generate_json", action="store_true", default=False, help="Generate JSON output")
|
|
parser.add_argument("-H", "--html", dest="generate_html", action="store_true", default=False, help="Generate HTML output")
|
|
|
|
options = parser.parse_args()
|
|
flag = False
|
|
|
|
TOP_DIR = options.dir
|
|
scan(options.dir + '/platforms')
|
|
|
|
if options.generate_json:
|
|
flag = True
|
|
print(generate_json())
|
|
|
|
if options.generate_html:
|
|
flag = True
|
|
print(generate_html())
|
|
|
|
if not flag:
|
|
parser.print_help()
|
|
|
|
main()
|