190 lines
7.5 KiB
Python
190 lines
7.5 KiB
Python
#!/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(
|
|
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<DoubleWordRegisterCollection>, 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("}")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
extractor = SVDExtractor("esp32s3.svd")
|
|
# extractor.extract(
|
|
# "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<ISPIPeripheral>"],
|
|
# )
|
|
extractor.extract(
|
|
"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"],
|
|
)
|