#!/usr/bin/env python3 import xml.etree.ElementTree as ET class SVDExtractor: def __init__(self, filename): self.tree = ET.parse(filename) self.root = self.tree.getroot() self.peripherals = self.root.find("peripherals") def extract_register_collection( self, peripheral_to_print, namespace, generated_peripheral_name, imports=None, extra_subclasses=None, ): for peripheral in self.peripherals.iter("peripheral"): peripheral_name = peripheral.find("name").text if peripheral_name != peripheral_to_print: continue register_list = dict() peripheral_size = int(peripheral.find("addressBlock").find("size").text, 0) registers = peripheral.find("registers") if imports is not None: for i in imports: print(f"using {i};") print() print(f"namespace {namespace}") print("{") print(f" public class {generated_peripheral_name} : ", end="") if extra_subclasses is not None: for esc in extra_subclasses: print(f"{esc}, ", end="") print( "IDoubleWordPeripheral, IProvidesRegisterCollection, IKnownSize" ) print(" {") print(" public GPIO IRQ { get; private set; }") print( " public DoubleWordRegisterCollection RegistersCollection { get; }" ) print(f" public long Size => 0x1000; // {hex(peripheral_size)}") print(" private readonly Machine machine;") print() print( f" public {generated_peripheral_name}(Machine machine) : base(machine)" ) print(" {") print(" this.machine = machine;") print() print(" IRQ = new GPIO();") print() print( " RegistersCollection = new DoubleWordRegisterCollection(this);" ) print(" DefineRegisters();") print(" Reset();") print(" }") print() print(" private void DefineRegisters()") print(" {") for register in registers.iter("register"): register_name = register.find("name").text register_description = register.find("description").text register_offset = int(register.find("addressOffset").text, 0) register_default = 0 register_reset_value_field = register.find("resetValue") if register_reset_value_field is not None: register_default = int(register_reset_value_field.text, 0) register_list[register_offset] = register_name if "\n" in register_description: raise Exception("Register description contains a newline") print(f" // {register_description}") print( f" Registers.{register_name}.Define(this, {hex(register_default)})" ) for field in register.find("fields").iter("field"): field_offset = int(field.find("bitOffset").text, 0) field_width = int(field.find("bitWidth").text, 0) field_name = field.find("name").text field_description = field.find("description").text field_access = field.find("access").text field_access_mask = "" if field_access == "read-write": field_access_mask = "FieldMode.Read | FieldMode.Write, " elif field_access == "read-only": field_access_mask = "FieldMode.Read, " elif field_access == "write-only": field_access_mask = "FieldMode.Write, " else: raise Exception( f"Unrecognized field access type: {field_access}" ) if "\n" in field_description: raise Exception("Field description contains a newline") if field_width == 1: print( f' .WithFlag({field_offset}, {field_access_mask}name: "{field_name}") // {field_description}' ) else: print( f' .WithValueField({field_offset}, {field_width}, {field_access_mask}name: "{field_name}") // {field_description}' ) print(" ;") print() print(" }") print() print(" public override void Reset()") print(" {") print(" RegistersCollection.Reset();") print(" UpdateInterrupts();") print(" }") print() print(" public uint ReadDoubleWord(long offset)") print(" {") print(" return RegistersCollection.Read(offset);") print(" }") print() print(" public void WriteDoubleWord(long offset, uint value)") print(" {") print(" RegistersCollection.Write(offset, value);") print(" }") print(" private void UpdateInterrupts()") print(" {") print(" var status = false;") print(' this.Log(LogLevel.Noisy, "Setting IRQ to {0}", status);') print(" IRQ.Set(status);") print(" }") print() print(" private enum Registers") print(" {") for offset, name in register_list.items(): print(f" {name} = {hex(offset)},") print(" }") print(" }") print("}") def extract_register_collection( self, peripheral_to_print, namespace, generated_peripheral_name, imports=None, extra_subclasses=None, ): for peripheral in self.peripherals.iter("peripheral"): peripheral_name = peripheral.find("name").text if peripheral_name != peripheral_to_print: continue register_list = dict() peripheral_size = int(peripheral.find("addressBlock").find("size").text, 0) registers = peripheral.find("registers") if imports is not None: for i in imports: print(f"using {i};") print() print(f"namespace {namespace}") print("{") print(f" public class {generated_peripheral_name} : ", end="") if extra_subclasses is not None: for esc in extra_subclasses: print(f"{esc}, ", end="") print( "IDoubleWordPeripheral, IKnownSize" ) print(" {") print(" public GPIO IRQ { get; private set; }") print( " private readonly DoubleWordRegisterCollection registers;" ) print(f" public long Size => 0x1000; // {hex(peripheral_size)}") print(" private readonly Machine machine;") print() print( f" public {generated_peripheral_name}(Machine machine) : base(machine)" ) print(" {") print(" this.machine = machine;") print() print(" IRQ = new GPIO();") print() print( " RegistersCollection = new DoubleWordRegisterCollection(this);" ) print(" DefineRegisters();") print(" Reset();") print(" }") print() print(" private void DefineRegisters()") print(" {") print(" var registersMap = new Dictionary") print(" {") for register in registers.iter("register"): register_name = register.find("name").text register_description = register.find("description").text register_offset = int(register.find("addressOffset").text, 0) register_default = 0 register_reset_value_field = register.find("resetValue") if register_reset_value_field is not None: register_default = int(register_reset_value_field.text, 0) register_list[register_offset] = register_name if "\n" in register_description: raise Exception("Register description contains a newline") print(f" // {hex(register_offset)}: {register_description}") print( f" {{(long)Registers.{register_name}, new DoubleWordRegister(this)" ) for field in register.find("fields").iter("field"): field_offset = int(field.find("bitOffset").text, 0) field_width = int(field.find("bitWidth").text, 0) field_name = field.find("name").text field_description = field.find("description").text field_access = field.find("access").text field_access_mask = "" if field_access == "read-write": field_access_mask = "FieldMode.Read | FieldMode.Write, " elif field_access == "read-only": field_access_mask = "FieldMode.Read, " elif field_access == "write-only": field_access_mask = "FieldMode.Write, " else: raise Exception( f"Unrecognized field access type: {field_access}" ) if "\n" in field_description: raise Exception("Field description contains a newline") if field_width == 1: print( f' .WithFlag({field_offset}, {field_access_mask}name: "{field_name}") // {field_description}' ) else: print( f' .WithValueField({field_offset}, {field_width}, {field_access_mask}name: "{field_name}") // {field_description}' ) print(" },") print(" };") print(" registers = new DoubleWordRegisterCollection(this, registersMap);") print(" }") print() print(" public override void Reset()") print(" {") print(" RegistersCollection.Reset();") print(" UpdateInterrupts();") print(" }") print() print(" public uint ReadDoubleWord(long offset)") print(" {") print(" return RegistersCollection.Read(offset);") print(" }") print() print(" public void WriteDoubleWord(long offset, uint value)") print(" {") print(" RegistersCollection.Write(offset, value);") print(" }") print(" private void UpdateInterrupts()") print(" {") print(" var status = false;") print(' this.Log(LogLevel.Noisy, "Setting IRQ to {0}", status);') print(" IRQ.Set(status);") print(" }") print() print(" private enum Registers") print(" {") for offset, name in register_list.items(): print(f" {name} = {hex(offset)},") print(" }") print(" }") print("}") if __name__ == "__main__": extractor = SVDExtractor("esp32s3.svd") # extractor.extract_register_collection( # "SPI1", # "Antmicro.Renode.Peripherals.SPI", # "ESP32_SPIController", # imports=[ # "System.Linq", # "System.Collections.Generic", # "Antmicro.Renode.Core", # "Antmicro.Renode.Core.Structure", # "Antmicro.Renode.Core.Structure.Registers", # "Antmicro.Renode.Logging", # "Antmicro.Renode.Peripherals.Bus", # "Antmicro.Renode.Peripherals.Memory", # "Antmicro.Renode.Peripherals.MTD", # ], # extra_subclasses=["NullRegistrationPointPeripheralContainer"], # ) # extractor.extract_register_collection( # "INTERRUPT_CORE0", # "Antmicro.Renode.Peripherals.IRQControllers", # "ESP32S3", # imports=[ # "System", # "System.Collections.ObjectModel", # "Antmicro.Renode.Peripherals.Bus", # "Antmicro.Renode.Core", # "Antmicro.Renode.Core.Structure.Registers", # "Antmicro.Renode.Logging", # "System.Collections.Generic", # "Antmicro.Renode.Utilities", # ], # extra_subclasses=["IIRQController", "INumberedGPIOOutput"], # ) extractor.extract_register_collection( "EXTMEM", "Antmicro.Renode.Peripherals.Miscellaneous", "ESP32S3", imports=[ "System", "Antmicro.Renode.Peripherals.Bus", "Antmicro.Renode.Core", "Antmicro.Renode.Peripherals", "Antmicro.Renode.Utilities", "Antmicro.Renode.Logging", "System.Collections.Generic", "Antmicro.Renode.Core.Structure.Registers", ], extra_subclasses=[], )