renode-esp32s3/svd-to-renode.py

352 lines
14 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_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<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("}")
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<long, DoubleWordRegister>")
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<ISPIPeripheral>"],
# )
# 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=[],
)