Skip to content

Commit

Permalink
Finish preparation for array feature
Browse files Browse the repository at this point in the history
  • Loading branch information
vkottler committed Oct 5, 2023
1 parent c968c16 commit 7b81322
Show file tree
Hide file tree
Showing 8 changed files with 90 additions and 34 deletions.
4 changes: 1 addition & 3 deletions ifgen/data/schemas/Struct.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ includes:
- has_description.yaml
- has_namespace.yaml
- has_json_indent.yaml
- has_expected_size.yaml

required: [fields]

Expand All @@ -15,9 +16,6 @@ properties:
type: boolean
default: true

expected_size:
type: integer

instances:
type: array
items:
Expand Down
1 change: 1 addition & 0 deletions ifgen/data/schemas/StructField.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
includes:
- has_description.yaml
- has_volatile.yaml
- has_expected_size.yaml

required: [name, type]

Expand Down
4 changes: 4 additions & 0 deletions ifgen/data/schemas/has_expected_size.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
properties:
expected_size:
type: integer
29 changes: 21 additions & 8 deletions ifgen/struct/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,11 @@ def struct_fields(task: GenerateTask, writer: IndentedFileWriter) -> None:
with writer.trailing_comment_lines(style=CommentStyle.C_DOXYGEN) as lines:
# Fields.
for field in task.instance["fields"]:
enforce_expected_size(
task.env.size(field["type"]),
field,
f"{task.name}.{field['name']}",
)
lines.append(struct_line(field["name"], field, field["volatile"]))

lines.append(("", None))
Expand Down Expand Up @@ -94,6 +99,20 @@ def struct_instance(
)


def enforce_expected_size(
size: int, data: dict[str, Any], assert_msg: str
) -> None:
"""Enforce an expected-size field."""

# If expected size is set, verify it.
if "expected_size" in data:
assert data["expected_size"] == size, (
assert_msg,
data["expected_size"],
size,
)


def create_struct(task: GenerateTask) -> None:
"""Create a header file based on a struct definition."""

Expand All @@ -115,15 +134,9 @@ def create_struct(task: GenerateTask) -> None:
f"{task.name}'s identifier.",
)
)
size = task.env.types.size(task.name)

# If expected size is set, verify it.
if "expected_size" in task.instance:
assert task.instance["expected_size"] == size, (
task.name,
task.instance["expected_size"],
size,
)
size = task.env.types.size(task.name)
enforce_expected_size(size, task.instance, task.name)

lines.append(
(
Expand Down
5 changes: 2 additions & 3 deletions ifgen/svd/group/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,8 @@ def struct_data(group: PeripheralGroup, structs: StructMap) -> dict[str, Any]:
peripheral.handle_description(data)

data["instances"] = [struct_instance(x) for x in group.peripherals]
data["fields"] = struct_fields(peripheral.registers, structs)

# let's compute expected size?
size, data["fields"] = struct_fields(peripheral.registers, structs)
data["expected_size"] = size

data.update(DEFAULT_STRUCT)
return data
Expand Down
51 changes: 32 additions & 19 deletions ifgen/svd/group/fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,45 +13,58 @@
DEFAULT_STRUCT = {"stream": False, "codec": False}


def handle_cluster(cluster: Cluster, structs: StructMap) -> StructField:
def handle_cluster(
cluster: Cluster, structs: StructMap
) -> tuple[int, StructField]:
"""Handle a cluster element."""

# Register a struct for this cluster. Should we use a namespace for this?
cluster_struct: dict[str, Any] = cluster.handle_description()
cluster_struct["fields"] = struct_fields(cluster.children, structs)
size, cluster_struct["fields"] = struct_fields(cluster.children, structs)
cluster_struct["expected_size"] = size
cluster_struct.update(DEFAULT_STRUCT)

# compute expected size?

structs[cluster.name] = cluster_struct

# This needs to be an array element somehow. Use a namespace?
result: StructField = {"name": cluster.name}
result: StructField = {"name": cluster.name, "expected_size": size}
cluster.handle_description(result)
return result
return size, result


def handle_register(register: Register) -> StructField:
def handle_register(register: Register) -> tuple[int, StructField]:
"""Handle a register entry."""

# handle register is array + get size from peripheral if necessary
# assert "size" in register.raw_data, register.name
# size = register.raw_data["size"]
# data = {"name": register.name, "type": f"uint{size}_t"}
data = {"name": register.name}

size = register.size
data = {
"name": register.name,
"type": register.c_type,
"expected_size": size,
}
register.handle_description(data)
return data
return size, data


def struct_fields(
registers: RegisterData, structs: StructMap
) -> list[StructField]:
registers: RegisterData, structs: StructMap, size: int = None
) -> tuple[int, list[StructField]]:
"""Generate data for struct fields."""

return [
handle_cluster(item, structs)
if isinstance(item, Cluster)
else handle_register(item)
for item in registers
]
fields = []

if size is None:
size = 0

for item in registers:
inst_size, field = (
handle_cluster(item, structs)
if isinstance(item, Cluster)
else handle_register(item)
)
fields.append(field)
size += inst_size

return size, fields
6 changes: 5 additions & 1 deletion ifgen/svd/model/derived.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,11 @@ class DerivedMixin(StringKeyValueMixin):
@property
def derived_elem(self: T) -> T:
"""Get the derived element."""
return getattr(self, "derived_from") # type: ignore

result = getattr(self, "derived_from", None)
if result is None:
result = self
return result

@property
def name(self) -> str:
Expand Down
24 changes: 24 additions & 0 deletions ifgen/svd/model/peripheral.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,23 @@ class Register(DerivedMixin):
fields: Optional[FieldMap]
peripheral: "Peripheral"

@property
def bits(self) -> int:
"""Get the size of this register in bits."""
result = self.raw_data.get("size", self.peripheral.bits)
assert result is not None
return int(result)

@property
def size(self) -> int:
"""Get the size of this register in bytes."""
return self.bits // 8

@property
def c_type(self) -> str:
"""Get the C type for this register."""
return f"uint{self.bits}_t"

@classmethod
def string_keys(cls) -> Iterable[StringKeyVal]:
"""Get string keys for this instance type."""
Expand Down Expand Up @@ -102,6 +119,13 @@ class Peripheral(DerivedMixin):

registers: RegisterData

@property
def bits(self) -> Optional[int]:
"""Get size for this peripheral in bits."""

result = self.derived_elem.raw_data.get("size")
return int(result) if result is not None else None

@property
def base_name(self) -> str:
"""Get the base peripheral name."""
Expand Down

0 comments on commit 7b81322

Please sign in to comment.