| #!/usr/bin/env python3 |
| # Copyright lowRISC contributors. |
| # Licensed under the Apache License, Version 2.0, see LICENSE for details. |
| # SPDX-License-Identifier: Apache-2.0 |
| r"""Top Module Documentation Generator |
| """ |
| import os |
| from tabulate import tabulate |
| |
| TABLE_HEADER = '''<!-- |
| DO NOT EDIT THIS FILE DIRECTLY. |
| It has been generated with the following command: |
| ''' |
| |
| |
| def set_md_table_font_size(row, size): |
| """Wrap each row element with HTML tags and specify font size""" |
| for k, elem in enumerate(row): |
| row[k] = '<p style="font-size:' + str(size) + '">' + elem + '</p>' |
| return row |
| |
| |
| def create_pinout_table(top, c_helper, target): |
| """Create the pinout table for a specific target and extract some stats""" |
| header = [ |
| "Pad Name", "Type", "Bank", "Connection", "Special Function", |
| "Pinmux Insel Constant / Muxed Output Index", "Description" |
| ] |
| table_rows = [set_md_table_font_size(header, "smaller")] |
| colalign = ("center", ) * len(header) |
| |
| # Pad stats |
| stats = {} |
| stats['muxed'] = 0 |
| stats['direct'] = 0 |
| stats['manual'] = 0 |
| |
| # get all pads for this target |
| pads = top['pinout']['pads'] + target['pinout']['add_pads'] |
| remove_ports = target['pinout']['remove_ports'] |
| remove_pads = target['pinout']['remove_pads'] |
| special_signals = target['pinmux']['special_signals'] |
| |
| # map pad names to special function signals |
| special_pads = {} |
| for sig in special_signals: |
| special_pads.update({sig['pad']: {'name': sig['name'], |
| 'desc': sig['desc']}}) |
| |
| i = 2 # insel enum starts at 2 |
| j = 0 # mio_out enum starts at 0 |
| for pad in pads: |
| # get the corresponding insel constant and MIO output index |
| if pad['connection'] == 'muxed': |
| name, _, _ = c_helper.pinmux_insel.constants[i] |
| insel = name.as_c_enum() |
| name, _, _ = c_helper.pinmux_mio_out.constants[j] |
| mio_out = name.as_c_enum() |
| i += 1 |
| j += 1 |
| else: |
| insel = "-" |
| mio_out = "-" |
| # check whether this pad/port needs to be dropped |
| if pad['name'] in remove_ports: |
| continue |
| if pad['name'] in remove_pads: |
| continue |
| # gather some stats |
| stats[pad['connection']] += 1 |
| # annotate special functions |
| if pad['name'] in special_pads: |
| special_func = special_pads[pad['name']]['name'] |
| desc = pad['desc'] + " / " + special_pads[pad['name']]['desc'] |
| else: |
| special_func = "-" |
| desc = pad['desc'] |
| row = [ |
| pad['name'], |
| pad['type'], |
| pad['bank'], |
| pad['connection'], |
| special_func, |
| insel + ' / ' + mio_out, |
| desc |
| ] |
| table_rows.append(set_md_table_font_size(row, "smaller")) |
| |
| ret_str = tabulate(table_rows, |
| headers="firstrow", |
| tablefmt="pipe", |
| colalign=colalign) |
| |
| return ret_str, stats |
| |
| |
| def create_pinmux_table(top, c_helper): |
| """Create the pinmux connectivity table""" |
| header = [ |
| "Module / Signal", "Connection", "Pad", |
| "Pinmux Outsel Constant / Peripheral Input Index", "Description" |
| ] |
| table_rows = [set_md_table_font_size(header, "smaller")] |
| colalign = ("center", ) * len(header) |
| |
| i = 3 # outsel enum starts at 3 |
| j = 0 # periph_input enum starts at 0 |
| for sig in top['pinmux']['ios']: |
| port = sig['name'] |
| if sig['width'] > 1: |
| port += '[' + str(sig['idx']) + ']' |
| pad = sig['pad'] if sig['pad'] else '-' |
| # get the corresponding insel constant |
| if sig['connection'] == 'muxed' and sig['type'] in ['inout', 'output']: |
| name, _, _ = c_helper.pinmux_outsel.constants[i] |
| outsel = name.as_c_enum() |
| i += 1 |
| else: |
| outsel = "-" |
| # get the corresponding peripheral input index |
| if sig['connection'] == 'muxed' and sig['type'] in ['inout', 'input']: |
| name, _, _ = c_helper.pinmux_peripheral_in.constants[j] |
| periph_in = name.as_c_enum() |
| j += 1 |
| else: |
| periph_in = "-" |
| row = [ |
| port, |
| sig['connection'], |
| pad, |
| outsel + " / " + periph_in, |
| sig['desc'] |
| ] |
| table_rows.append(set_md_table_font_size(row, "smaller")) |
| |
| return tabulate(table_rows, |
| headers="firstrow", |
| tablefmt="pipe", |
| colalign=colalign) |
| |
| |
| def gen_pinmux_docs(top, c_helper, out_path): |
| """Generate target summary table and linked subtables""" |
| |
| pinmux_path = out_path / '../ip/pinmux/doc' |
| doc_path = out_path / 'ip/pinmux/doc/autogen' |
| doc_path.mkdir(parents=True, exist_ok=True) |
| |
| # this is used to create relative hyperlinks from the summary table to |
| # the individual target tables. |
| relpath_prefix = os.path.relpath(doc_path.resolve(), pinmux_path.resolve()) |
| |
| topname = top['name'] |
| gencmd = ("util/topgen.py -t hw/top_{topname}/data/top_{topname}.hjson " |
| "-o hw/top_{topname}/\n\n".format(topname=topname)) |
| |
| header = [ |
| "Target Name", "#IO Banks", "#Muxed Pads", "#Direct Pads", |
| "#Manual Pads", "#Total Pads", "Pinout / Pinmux Tables" |
| ] |
| table_rows = [header] |
| colalign = ("center", ) * len(header) |
| |
| for target in top['targets']: |
| |
| # create pinout/pinmux tables for this target |
| pinout_table = '---\n' |
| pinout_table += 'title: ' + target['name'].upper() |
| pinout_table += ' Target Pinout and Pinmux Connectivity\n' |
| pinout_table += '---\n' |
| pinout_table += TABLE_HEADER + gencmd + "-->\n\n" |
| pinout_table += '## Pinout Table\n\n' |
| table_str, stats = create_pinout_table(top, c_helper, target) |
| pinout_table += table_str + '\n' |
| pinout_table += '## Pinmux Connectivity\n\n' |
| pinout_table += create_pinmux_table(top, c_helper) |
| pinout_table += "\n" |
| |
| pinout_table_path = doc_path / ("pinout_" + target['name'] + ".md") |
| with open(pinout_table_path, 'w') as outfile: |
| outfile.write(pinout_table) |
| |
| # gather some statistics |
| num_banks = len(top['pinout']['banks']) |
| # create summary table entry |
| pinout_table_relpath = relpath_prefix + "/pinout_" + target['name'] + "/index.html" |
| row = [ |
| target['name'].upper(), |
| num_banks, |
| stats['muxed'], |
| stats['direct'], |
| stats['manual'], |
| stats['muxed'] + stats['direct'] + stats['manual'], |
| "[Pinout Table](" + str(pinout_table_relpath) + ")" |
| ] |
| table_rows.append(row) |
| |
| summary_table = tabulate(table_rows, |
| headers="firstrow", |
| tablefmt="pipe", |
| colalign=colalign) |
| summary_table = TABLE_HEADER + gencmd + "-->\n\n" + summary_table + "\n" |
| |
| target_table_path = doc_path / "targets.md" |
| with open(target_table_path, 'w') as target_outfile: |
| target_outfile.write(summary_table) |
| |
| |
| def gen_top_docs(top, c_helper, out_path): |
| # create pinout / pinmux specific tables for all targets |
| gen_pinmux_docs(top, c_helper, out_path) |