|
| 1 | +#!/usr/bin/env python3 |
| 2 | +import argparse |
| 3 | +import pathlib |
| 4 | +from cmsis_svd import SVDParser |
| 5 | +from cmsis_svd.model import SVDAccessType, SVDCPUNameType |
| 6 | + |
| 7 | +def instance_to_type(name): |
| 8 | + return f"{name}_t" |
| 9 | + |
| 10 | +def sized_int(bit_size): |
| 11 | + return f"::bitfilled::sized_unsigned_t<{bit_size // 8}>" |
| 12 | + |
| 13 | +def is_bitband_range(address): |
| 14 | + return address >= 0x40000000 and address < 0x42000000 |
| 15 | + |
| 16 | +def convert_access(svd_access): |
| 17 | + match svd_access: |
| 18 | + case SVDAccessType.READ_ONLY: |
| 19 | + return "r" |
| 20 | + case SVDAccessType.WRITE_ONLY | SVDAccessType.WRITE_ONCE: |
| 21 | + return "w" |
| 22 | + case SVDAccessType.READ_WRITE | SVDAccessType.READ_WRITE_ONCE | _: |
| 23 | + return "rw" |
| 24 | + |
| 25 | +def generate_peripheral(peripheral, bitband): |
| 26 | + peripheral_name = peripheral.name |
| 27 | + if len(peripheral.group_name): |
| 28 | + peripheral_name = peripheral.group_name |
| 29 | + |
| 30 | + parts = [] |
| 31 | + parts.append( |
| 32 | + f"struct {instance_to_type(peripheral_name)} {{") |
| 33 | + # TODO: only use bitband if all peripherals of the chip are in bitband range |
| 34 | + parts.append( |
| 35 | + " using mmr_ops = ::bitfilled::bitband<PERIPH_BASE>;" if bitband and is_bitband_range(peripheral.base_address) else |
| 36 | + " using mmr_ops = ::bitfilled::base;") |
| 37 | + |
| 38 | + # TODO: in the first round of iteration, generate enum types where enumeratedValues is provided |
| 39 | + # also de-duplicate enum types across registers |
| 40 | + |
| 41 | + nametrim = peripheral.name + "_" |
| 42 | + offset = 0 |
| 43 | + for register in peripheral.get_registers(): |
| 44 | + # filling gaps in the register map with reserved |
| 45 | + if (offset < register.address_offset): |
| 46 | + reserved_size = (register.address_offset - offset) * 8 // register.size |
| 47 | + parts.append( |
| 48 | + f" BF_MMREG_RESERVED({register.size // 8}, {reserved_size})") |
| 49 | + |
| 50 | + # define the register |
| 51 | + regname = register.name.removeprefix(nametrim) |
| 52 | + regnametype = instance_to_type(regname) |
| 53 | + parts.append( |
| 54 | + f" struct {regnametype} : BF_MMREG({sized_int(register.size)}, {convert_access(register.access)}, mmr_ops) {{\n" |
| 55 | + f" BF_COPY_SUPERCLASS({regnametype});") |
| 56 | + |
| 57 | + # define register fields |
| 58 | + for field in register.get_fields(): |
| 59 | + # TODO: group the fields into bitfieldset, if they are contiguous, share properties and are named accordingly |
| 60 | + |
| 61 | + access = field.access if field.access else register.access |
| 62 | + lsb = field.bit_offset |
| 63 | + msb = field.bit_offset + field.bit_width - 1 |
| 64 | + parts.append( |
| 65 | + f" BF_MMREGBITS({sized_int(register.size)}, {convert_access(access)}, {lsb}, {msb}) {field.name};") |
| 66 | + |
| 67 | + parts.append( |
| 68 | + f" }} {regname};") |
| 69 | + offset = register.address_offset + register.size // 8 |
| 70 | + |
| 71 | + parts.append( |
| 72 | + "};") |
| 73 | + return "\n".join(parts) |
| 74 | + |
| 75 | +if __name__ == "__main__": |
| 76 | + parser = argparse.ArgumentParser( |
| 77 | + description="Parse an SVD file and generate bitfilled register map for a peripheral type." |
| 78 | + ) |
| 79 | + parser.add_argument( |
| 80 | + "path", |
| 81 | + type=pathlib.Path, |
| 82 | + help="Path to the input SVD file" |
| 83 | + ) |
| 84 | + parser.add_argument( |
| 85 | + "peripheral", |
| 86 | + type=str, |
| 87 | + help="Name of the peripheral or peripheral group for code generation" |
| 88 | + ) |
| 89 | + |
| 90 | + args = parser.parse_args() |
| 91 | + |
| 92 | + parser = SVDParser.for_xml_file(str(args.path)) |
| 93 | + device = parser.get_device() |
| 94 | + bitband_support = device.cpu.name == SVDCPUNameType.CM3 or device.cpu.name == SVDCPUNameType.CM4 |
| 95 | + |
| 96 | + peripherals = device.get_peripherals() |
| 97 | + if args.peripheral == None: |
| 98 | + raise ValueError("Peripheral name must be provided") |
| 99 | + |
| 100 | + for peripheral in peripherals: |
| 101 | + if peripheral.name == args.peripheral or peripheral.group_name == args.peripheral: |
| 102 | + print(generate_peripheral(peripheral, bitband_support)) |
| 103 | + exit(0) |
| 104 | + |
| 105 | + raise ValueError(f"Peripheral {args.peripheral} not found in the SVD file") |
0 commit comments