stricter irq parsing.

This commit is contained in:
Dario Nieuwenhuis 2022-01-24 22:57:06 +01:00
parent 2a14936a5e
commit c1c3d8b354

View File

@ -15,37 +15,218 @@ def get(nvic_name, nvic_version, core):
def parse(): def parse():
print("parsing interrupts") print("parsing interrupts")
for f in glob('sources/cubedb/mcu/IP/NVIC*_Modes.xml'): for f in glob('sources/cubedb/mcu/IP/NVIC*_Modes.xml'):
if 'STM32MP1' in f:
continue
f = f.replace(os.path.sep, '/') f = f.replace(os.path.sep, '/')
ff = removeprefix(f, 'sources/cubedb/mcu/IP/') ff = removeprefix(f, 'sources/cubedb/mcu/IP/')
ff = removesuffix(ff, '_Modes.xml') ff = removesuffix(ff, '_Modes.xml')
[nvic_name, nvic_version] = ff.split('-') [nvic_name, nvic_version] = ff.split('-')
chip_irqs = {} irqs = {}
r = xmltodict.parse(open(f, 'rb')) r = xmltodict.parse(open(f, 'rb'))
irqs = next(filter(lambda x: x['@Name'] == 'IRQn', r['IP']['RefParameter'])) xml_irqs = next(filter(lambda x: x['@Name'] == 'IRQn', r['IP']['RefParameter']))
for irq in irqs['PossibleValue']: for irq in xml_irqs['PossibleValue']:
value = irq['@Value'] value = irq['@Value']
parts = value.split(':') parts = value.split(':')
irq_name = removesuffix(parts[0], "_IRQn")
# Interrupt name
name = removesuffix(parts[0], "_IRQn")
if name in irqs:
continue
print(f'{name:25} {nvic_version:12} {nvic_name:5} {parts[1]:8} {parts[2]:45} {parts[3]:45} {parts[4]:15}')
# Flags.
# Y
# unknown, it's in all of them
# H3, nHS
# ???
# 2V, 3V, nV, 2V1
# unknown, it has to do with the fact the irq is shared among N peripehrals
# DMA, DMAL0, DMAF0, DMAL0_DMAMUX, DMAF0_DMAMUX
# special format for DMA
# DFSDM
# special format for DFSDM
# EXTI
# special format for EXTI
flags = parts[1].split(',')
# F100xE MISC_REMAP remaps some DMA IRQs, so ST decided to give two names # F100xE MISC_REMAP remaps some DMA IRQs, so ST decided to give two names
# to the same IRQ number. # to the same IRQ number.
if nvic_version == 'STM32F100E' and irq_name == 'DMA2_Channel4_5': if nvic_version == 'STM32F100E' and name == 'DMA2_Channel4_5':
continue
signals = []
if name in ['NonMaskableInt', 'HardFault', 'MemoryManagement', 'BusFault', 'UsageFault', 'SVCall', 'DebugMonitor', 'PendSV', 'SysTick']:
pass
elif any(f in flags for f in ['DMA', 'DMAL0', 'DMAF0', 'DMAL0_DMAMUX', 'DMAF0_DMAMUX']):
dmas = parts[3].split(',')
chans = parts[4].split(';')
assert len(dmas) == len(chans)
for i in range(len(dmas)):
dma = dmas[i]
if ',' in chans[i]:
ch_from, ch_to = chans[i].split(',')
else:
ch_from = chans[i]
ch_to = chans[i]
ch_from = int(ch_from)
ch_to = int(ch_to)
for ch in range(ch_from, ch_to+1):
signals.append((dma, f'CH{ch}'))
elif name == 'DMAMUX1': # TODO does DMAMUX have more irq signals? seen in U5
signals.append(('DMAMUX1', 'OVR'))
elif name == 'DMAMUX1_S': # TODO does DMAMUX have more irq signals? seen in U5
signals.append(('DMAMUX1', 'OVR'))
elif name == 'DMAMUX_OVR':
signals.append(('DMAMUX1', 'OVR'))
elif name == 'DMAMUX1_OVR':
signals.append(('DMAMUX1', 'OVR'))
elif name == 'DMAMUX2_OVR':
signals.append(('DMAMUX2', 'OVR'))
elif 'DMAMUX' in flags:
assert False # should've been handled above
elif 'EXTI' in flags:
for signal in parts[2].split(','):
signals.append(('EXTI', signal))
elif name == 'FLASH':
signals.append(('FLASH', 'GLOBAL'))
elif name == 'CRS':
signals.append(('RCC', 'CRS'))
elif name == 'RCC':
signals.append(('RCC', 'GLOBAL'))
else:
if parts[2] == '':
continue continue
peri_names = parts[2].split(',') peri_names = parts[2].split(',')
if len(peri_names) == 1 and peri_names[0] == '':
continue name2 = name
elif len(peri_names) == 1 and (peri_names[0] == 'DMA' or peri_names[0].startswith("DMAL")): if name2 == 'USBWakeUp':
peri_names = [parts[3]] name2 = 'USB_WKUP'
split = split_interrupts(peri_names, irq_name) if name2 == 'USBWakeUp_RMP':
for p in peri_names: name2 = 'USB_WKUP'
if p not in chip_irqs: if name2.endswith('_S'):
chip_irqs[p] = {} name2 = removesuffix(name2, '_S')
merge_peri_irq_signals(chip_irqs[p], split[p])
chip_interrupts[(nvic_name, nvic_version)] = chip_irqs peri_signals = {p: [] for p in peri_names}
curr_peris = None
if len(peri_names) == 1:
curr_peris = peri_names
# Parse IRQ signals from the IRQ name.
for part in tokenize_name(name2):
if part == 'TAMPER':
part = 'TAMP'
if part == 'LSECSS':
signals.append(('RCC', 'LSECSS'))
elif part == 'CSS':
signals.append(('RCC', 'CSS'))
elif part == 'LSE':
signals.append(('RCC', 'LSE'))
elif part == 'CRS':
signals.append(('RCC', 'CRS'))
elif pp := match_peris(peri_names, part):
curr_peris = pp
else:
assert curr_peris is not None
for p in curr_peris:
peri_signals[p].append(part)
for p, ss in peri_signals.items():
known = valid_signals(p)
# If we have no signals for the peri, assume it's "global" so assign it all known ones
if ss == []:
if p.startswith('COMP'):
ss = ['WKUP']
else:
ss = known
for s in ss:
if s not in known:
raise Exception(f'Unknown signal {s} for peri {p}, known={known}')
signals.append((p, s))
for (peri, signal) in signals:
print(f' {peri}:{signal}')
irqs[name] = signals
irqs2 = {}
for name, signals in irqs.items():
for (p, s) in signals:
irqs2.setdefault(p, {}).setdefault(s, []).append(name)
chip_interrupts[(nvic_name, nvic_version)] = irqs2
def tokenize_name(name):
# Treat IRQ names are "tokens" separated by `_`, except some tokens
# contain `_` themselves, such as `C1_RX`.
r = re.compile('(SPDIF_RX|EP\d+_(IN|OUT)|OTG_FS|OTG_HS|USB_FS|C1_RX|C1_TX|C2_RX|C2_TX|[A-Z0-9]+(_\d+)*)_*')
name = name.upper()
res = []
i = 0
while i < len(name):
m = r.match(name, i)
assert m is not None
res.append(m.group(1))
i = m.end()
return res
def match_peris(peris, name):
if name == 'USB_FS' and 'USB' in peris:
return ['USB']
if name == 'OTG_HS' and 'USB_OTG_HS' in peris:
return ['USB_OTG_HS']
if name == 'OTG_FS' and 'USB_OTG_FS' in peris:
return ['USB_OTG_FS']
if name == 'USB' and 'USB_DRD_FS' in peris:
return ['USB_DRD_FS']
if name == 'UCPD1_2' and 'UCPD1' in peris and 'UCPD2' in peris:
return ['UCPD1', 'UCPD2']
if name == 'ADC1' and 'ADC' in peris:
return ['ADC']
if name == 'CEC' and 'HDMI_CEC' in peris:
return ['HDMI_CEC']
if name == 'SPDIF_RX' and 'SPDIFRX1' in peris:
return ['SPDIFRX1']
if name == 'SPDIF_RX' and 'SPDIFRX' in peris:
return ['SPDIFRX']
if name == 'CAN1' and 'CAN' in peris:
return ['CAN']
if name == 'TEMP' and 'TEMPSENS' in peris:
return ['TEMPSENS']
if name == 'DSI' and 'DSIHOST' in peris:
return ['DSIHOST']
if name == 'HRTIM1' and 'HRTIM' in peris:
return ['HRTIM']
if name == 'GTZC' and 'GTZC_S' in peris:
return ['GTZC_S']
if name == 'TZIC' and 'GTZC_S' in peris:
return ['GTZC_S']
res = []
if m := re.fullmatch('(I2C|[A-Z]+)(\d+(_\d+)*)', name):
name = m.group(1)
for n in m.group(2).split('_'):
p = f'{name}{n}'
if p not in peris:
return []
res.append(p)
else:
for p in peris:
if p == name or (p.startswith(name) and re.fullmatch('\d+', removeprefix(p, name))):
res.append(p)
return res
def merge_peri_irq_signals(peri_irqs, additional): def merge_peri_irq_signals(peri_irqs, additional):
@ -55,61 +236,39 @@ def merge_peri_irq_signals(peri_irqs, additional):
peri_irqs[key].append(value) peri_irqs[key].append(value)
def split_interrupts(peri_names, irq_name):
split = {}
for p in peri_names:
split[p] = remap_interrupt_signals(p, irq_name)
return split
irq_signals_map = { irq_signals_map = {
'CAN': ['TX', 'RX0', 'RX1', 'SCE'], 'CAN': ['TX', 'RX0', 'RX1', 'SCE'],
'FDCAN': ['IT0', 'IT1', 'CAL'],
'I2C': ['ER', 'EV'], 'I2C': ['ER', 'EV'],
'TIM': ['BRK', 'UP', 'TRG', 'COM'], 'FMPI2C': ['ER', 'EV'],
'HRTIM': ['Master', 'TIMA', 'TIMB', 'TIMC', 'TIMD', 'TIME', 'TIMF'] 'TIM': ['BRK', 'UP', 'TRG', 'COM', 'CC'],
'HRTIM': ['Master', 'TIMA', 'TIMB', 'TIMC', 'TIMD', 'TIME', 'TIMF'],
'RTC': ['ALARM', 'WKUP', 'TAMP', 'STAMP', 'SSRU'],
'SUBGHZ': ['RADIO'],
'IPCC': ['C1_RX', 'C1_TX', 'C2_RX', 'C2_TX'],
'HRTIM': ['MASTER', 'TIMA', 'TIMB', 'TIMC', 'TIMD', 'TIME', 'TIMF', 'FLT'],
'COMP': ['WKUP', 'ACQ'],
'RCC': ['RCC', 'CRS'],
'MDIOS': ['GLOBAL', 'WKUP'],
'ETH': ['GLOBAL', 'WKUP'],
'LTDC': ['GLOBAL', 'ER'],
'DFSDM': ['FLT0', 'FLT1', 'FLT2', 'FLT3', 'FLT4', 'FLT5', 'FLT6', 'FLT7'],
'MDF': ['FLT0', 'FLT1', 'FLT2', 'FLT3', 'FLT4', 'FLT5', 'FLT6', 'FLT7'],
'PWR': ['S3WU'],
'GTZC': ['GLOBAL', 'ILA'],
'WWDG': ['GLOBAL', 'RST'],
'USB_OTG_FS': ['GLOBAL', 'EP1_OUT', 'EP1_IN', 'WKUP'],
'USB_OTG_HS': ['GLOBAL', 'EP1_OUT', 'EP1_IN', 'WKUP'],
'USB': ['LP', 'HP', 'WKUP'],
} }
def remap_interrupt_signals(peri_name, irq_name): def valid_signals(peri):
if peri_name == irq_name: for prefix, signals in irq_signals_map.items():
return expand_all_irq_signals(peri_name, irq_name) if peri.startswith(prefix):
if (peri_name.startswith('DMA') or peri_name.startswith('BDMA')) and irq_name.startswith(peri_name):
return {irq_name: irq_name}
if peri_name.startswith('USART') and irq_name.startswith(peri_name):
return {'GLOBAL': irq_name}
if peri_name in irq_name:
signals = {}
start = irq_name.index(peri_name)
regexp = re.compile('(_[^_]+)')
if match := regexp.findall(irq_name, start):
for m in match:
signal = removeprefix(m, '_').strip()
if is_valid_irq_signal(peri_name, signal):
signals[signal] = irq_name
else:
signals = expand_all_irq_signals(peri_name, irq_name)
return signals return signals
else: return ['GLOBAL']
return {'GLOBAL': irq_name}
def is_valid_irq_signal(peri_name, signal):
for prefix, signals in irq_signals_map.items():
if peri_name.startswith(prefix):
return signal in signals
return False
def expand_all_irq_signals(peri_name, irq_name):
expanded = {}
for prefix, signals in irq_signals_map.items():
if peri_name.startswith(prefix):
for s in irq_signals_map[prefix]:
expanded[s] = irq_name
return expanded
return {'GLOBAL': irq_name}
def filter_interrupts(peri_irqs, all_irqs): def filter_interrupts(peri_irqs, all_irqs):