Skip to content

Commit 2c99d44

Browse files
committed
Transitioned the in-memory representation of fpga definitions from json dicts to proto buffer objects.
1 parent b935cb0 commit 2c99d44

16 files changed

Lines changed: 164 additions & 153 deletions

apio/commands/apio_api.py

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -397,7 +397,7 @@ def _get_project_cli(
397397
"id": pr.fpga_id,
398398
"is-custom": apio_ctx.definitions.is_custom_fpga(pr.fpga_id),
399399
}
400-
fpga_dict["definition"] = pr.fpga_info
400+
fpga_dict["definition"] = proto_util.proto_to_json_dict(pr.fpga_definition)
401401
section_dict["fpga"] = fpga_dict
402402

403403
programmer_dict = {
@@ -478,10 +478,9 @@ def _get_boards_cli(
478478

479479
# -- Add board's fpga information.
480480
fpga_id = board_definition.fpga_id
481-
fpga_info = apio_ctx.definitions.fpgas.get(fpga_id, {})
482-
assert "id" not in fpga_info
481+
fpga_definition = apio_ctx.definitions.fpgas[fpga_id]
483482
fpga_dict = {"id": fpga_id}
484-
fpga_dict.update(fpga_info)
483+
fpga_dict.update(proto_util.proto_to_json_dict(fpga_definition))
485484
board_dict["fpga"] = fpga_dict
486485

487486
# -- Add board's programmer information.
@@ -552,8 +551,8 @@ def _get_fpgas_cli(
552551

553552
# -- Generate the fpgas section
554553
section = {}
555-
for fpga_id, fpga_info in apio_ctx.definitions.fpgas.items():
556-
section[fpga_id] = fpga_info
554+
for fpga_id, fpga_definition in apio_ctx.definitions.fpgas.items():
555+
section[fpga_id] = proto_util.proto_to_json_dict(fpga_definition)
557556

558557
top_dict["fpgas"] = section
559558

apio/commands/apio_boards.py

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
from apio.utils import util, cmd_util
2323
from apio.commands import options
2424
from apio.managers.examples import Examples
25+
from apio.common.proto.apio_common_pb2 import ApioArch
2526
from apio.apio_context import (
2627
ApioContext,
2728
PackagesPolicy,
@@ -36,7 +37,7 @@ class Entry:
3637

3738
# pylint: disable=too-many-instance-attributes
3839

39-
board: str
40+
board_id: str
4041
examples_count: str
4142
board_description: str
4243
fpga_arch: str
@@ -47,31 +48,30 @@ class Entry:
4748

4849
def sort_key(self):
4950
"""A key for sorting the fpga entries in our preferred order."""
50-
return (util.fpga_arch_sort_key(self.fpga_arch), self.board.lower())
51+
return (util.fpga_arch_sort_key(self.fpga_arch), self.board_id.lower())
5152

5253

53-
def _collect_board_entries(apio_ctx) -> List[Entry]:
54+
def _collect_board_entries(apio_ctx: ApioContext) -> List[Entry]:
5455

5556
# -- Get examples counts by board. This is a sparse dictionary.
5657
examples = Examples(apio_ctx)
5758
examples_counts: Dict[str, int] = examples.count_examples_by_board()
5859

5960
# -- Collect the boards info into a list of entires, one per board.
6061
result: List[Entry] = []
61-
for board, board_definition in apio_ctx.definitions.boards.items():
62+
for board_id, board_definition in apio_ctx.definitions.boards.items():
6263
fpga_id = board_definition.fpga_id
63-
fpga_info = apio_ctx.definitions.fpgas.get(fpga_id, {})
64-
65-
examples_count = " " + str(examples_counts.get(board, ""))
64+
fpga_definition = apio_ctx.definitions.fpgas[fpga_id]
65+
examples_count = " " + str(examples_counts.get(board_id, ""))
6666
board_description = board_definition.description
67-
fpga_arch = fpga_info.get("arch", "")
68-
fpga_size = fpga_info.get("size", "")
69-
fpga_part_num = fpga_info.get("part-num", "")
67+
fpga_arch = ApioArch.Name(fpga_definition.arch)
68+
fpga_size = fpga_definition.size
69+
fpga_part_num = fpga_definition.part_num
7070
programmer_id = board_definition.programmer.id
7171

7272
result.append(
7373
Entry(
74-
board=board,
74+
board_id=board_id,
7575
examples_count=examples_count,
7676
board_description=board_description,
7777
fpga_arch=fpga_arch,
@@ -127,12 +127,12 @@ def _list_boards(apio_ctx: ApioContext, verbose: bool):
127127

128128
# -- Collect row values.
129129
values = []
130-
values.append(entry.board)
130+
values.append(entry.board_id)
131131
values.append(str(entry.examples_count))
132132
if verbose:
133133
values.append(entry.board_description)
134134
values.append(entry.fpga_arch)
135-
values.append(str(entry.fpga_size))
135+
values.append(entry.fpga_size)
136136
if verbose:
137137
values.append(entry.fpga_id)
138138
values.append(entry.fpga_part_num)
@@ -169,7 +169,7 @@ def _list_boards_docs_format(apio_ctx: ApioContext):
169169
entries: List[Entry] = _collect_board_entries(apio_ctx)
170170

171171
# -- Determine column sizes
172-
w1 = max(len("BOARD"), *(len(entry.board) for entry in entries))
172+
w1 = max(len("BOARD"), *(len(entry.board_id) for entry in entries))
173173
w2 = max(len("SIZE"), *(len(entry.fpga_size) for entry in entries))
174174
w3 = max(
175175
len("DESCRIPTION"),
@@ -222,7 +222,7 @@ def _list_boards_docs_format(apio_ctx: ApioContext):
222222

223223
cwrite(
224224
"| {0} | {1} | {2} | {3} |\n".format(
225-
entry.board.ljust(w1),
225+
entry.board_id.ljust(w1),
226226
entry.fpga_size.ljust(w2),
227227
entry.board_description.ljust(w3),
228228
entry.fpga_part_num.ljust(w4),

apio/commands/apio_fpgas.py

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,20 +11,23 @@
1111
from datetime import date
1212
from pathlib import Path
1313
from dataclasses import dataclass
14-
from typing import List, Dict, Optional
14+
from typing import List, Dict, Optional, Tuple
1515
import click
1616
from rich.table import Table
1717
from rich import box
1818
from apio.common import apio_console
1919
from apio.common.apio_console import cout, ctable, cwrite
2020
from apio.common.apio_styles import INFO, BORDER, EMPH1
21+
from apio.common.proto.apio_common_pb2 import ApioArch
22+
from apio.common.proto.apio_definitions_pb2 import FpgaDefinition
23+
from apio.utils import proto_util
2124
from apio.apio_context import (
2225
ApioContext,
2326
PackagesPolicy,
2427
ProjectPolicy,
2528
RemoteConfigPolicy,
2629
)
27-
from apio.utils import util, cmd_util, resource_util
30+
from apio.utils import util, cmd_util
2831
from apio.commands import options
2932

3033

@@ -44,6 +47,16 @@ def sort_key(self):
4447
return (util.fpga_arch_sort_key(self.fpga_arch), self.fpga.lower())
4548

4649

50+
def _get_fpga_arch_params(fpga_definition: FpgaDefinition) -> Tuple[str, Dict]:
51+
"""Extracts the arch specific params of an fpga, Returns a tuple
52+
with the field name and the field value."""
53+
fpga_dict = proto_util.proto_to_json_dict(fpga_definition)
54+
arch = fpga_dict["arch"]
55+
field_name = arch + "-params"
56+
field_value = fpga_dict[field_name]
57+
return (field_name, field_value)
58+
59+
4760
def _collect_fpgas_entries(apio_ctx: ApioContext) -> List[Entry]:
4861
"""Returns a sorted list of supported fpgas entries."""
4962

@@ -56,15 +69,15 @@ def _collect_fpgas_entries(apio_ctx: ApioContext) -> List[Entry]:
5669

5770
# -- Collect all entries.
5871
result: List[Entry] = []
59-
for fpga_id, fpga_info in apio_ctx.definitions.fpgas.items():
72+
for fpga_id, fpga_definition in apio_ctx.definitions.fpgas.items():
6073
# -- Construct the Entry for this fpga.
6174
board_count = boards_counts.get(fpga_id, 0)
62-
fpga_arch = fpga_info.get("arch", "")
63-
fpga_part_num = fpga_info.get("part-num", "")
64-
fpga_size = fpga_info.get("size", "")
75+
fpga_arch = fpga_definition.arch
76+
fpga_part_num = fpga_definition.part_num
77+
fpga_size = fpga_definition.size
6578

6679
# -- Arch specific params summary string.
67-
_, params = resource_util.get_fpga_arch_params(fpga_info)
80+
_, params = _get_fpga_arch_params(fpga_definition)
6881
values = [f"\\[{v}]" for v in params.values()]
6982
fpga_params = " ".join(values)
7083

@@ -73,7 +86,7 @@ def _collect_fpgas_entries(apio_ctx: ApioContext) -> List[Entry]:
7386
Entry(
7487
fpga=fpga_id,
7588
board_count=board_count,
76-
fpga_arch=fpga_arch,
89+
fpga_arch=ApioArch.Name(fpga_arch),
7790
fpga_part_num=fpga_part_num,
7891
fpga_size=fpga_size,
7992
fpga_params=fpga_params,

apio/commands/apio_info.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
ProjectPolicy,
2727
RemoteConfigPolicy,
2828
)
29+
from apio.common.proto.apio_common_pb2 import ApioArch
2930
from apio.utils.cmd_util import ApioGroup, ApioSubgroup, ApioCommand
3031
from apio.common.apio_themes import THEMES_TABLE, THEME_LIGHT
3132
from apio.managers.remote_config import (
@@ -265,9 +266,9 @@ def _project_cli(
265266
table.add_row("Board definition", board_definition)
266267
table.add_row("FPGA id", fpga_id)
267268
table.add_row("FPGA definition", fpga_definition)
268-
table.add_row("FPGA part num", res.fpga_info.get("part-num", ""))
269-
table.add_row("FPGA Architecture", res.fpga_info.get("arch", ""))
270-
table.add_row("FPGA size", res.fpga_info.get("size", ""))
269+
table.add_row("FPGA part num", res.fpga_definition.part_num)
270+
table.add_row("FPGA Architecture", ApioArch.Name(res.fpga_definition.arch))
271+
table.add_row("FPGA size", res.fpga_definition.size)
271272
table.add_row("Programmer id", programmer_id)
272273
table.add_row("Programmer definition", programmer_definition)
273274

apio/common/proto/apio-common.proto

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,11 @@ syntax = "proto2";
1212
package apio.common.proto;
1313

1414
// The supported FPGA architectures.
15+
// Using lower case names to be json friendly.
1516
enum ApioArch {
16-
ICE40 = 1;
17-
ECP5 = 2;
18-
GOWIN = 3;
19-
XILINX = 4;
17+
ice40 = 1;
18+
ecp5 = 2;
19+
gowin = 3;
20+
xilinx = 4;
2021
}
2122

apio/common/proto/apio_common_pb2.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626

2727

2828

29-
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n#apio/common/proto/apio-common.proto\x12\x11\x61pio.common.proto*6\n\x08\x41pioArch\x12\t\n\x05ICE40\x10\x01\x12\x08\n\x04\x45\x43P5\x10\x02\x12\t\n\x05GOWIN\x10\x03\x12\n\n\x06XILINX\x10\x04')
29+
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n#apio/common/proto/apio-common.proto\x12\x11\x61pio.common.proto*6\n\x08\x41pioArch\x12\t\n\x05ice40\x10\x01\x12\x08\n\x04\x65\x63p5\x10\x02\x12\t\n\x05gowin\x10\x03\x12\n\n\x06xilinx\x10\x04')
3030

3131
_globals = globals()
3232
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)

apio/common/proto/apio_common_pb2.pyi

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,11 @@ DESCRIPTOR: _descriptor.FileDescriptor
88

99
class ApioArch(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
1010
__slots__ = ()
11-
ICE40: _ClassVar[ApioArch]
12-
ECP5: _ClassVar[ApioArch]
13-
GOWIN: _ClassVar[ApioArch]
14-
XILINX: _ClassVar[ApioArch]
15-
ICE40: ApioArch
16-
ECP5: ApioArch
17-
GOWIN: ApioArch
18-
XILINX: ApioArch
11+
ice40: _ClassVar[ApioArch]
12+
ecp5: _ClassVar[ApioArch]
13+
gowin: _ClassVar[ApioArch]
14+
xilinx: _ClassVar[ApioArch]
15+
ice40: ApioArch
16+
ecp5: ApioArch
17+
gowin: ApioArch
18+
xilinx: ApioArch

apio/managers/apio_definitions.py

Lines changed: 19 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,10 @@
1717
import json5
1818
from apio.utils import proto_util
1919
from apio.common.apio_console import cout, cerror
20-
from apio.common.proto.apio_definitions_pb2 import BoardDefinition
20+
from apio.common.proto.apio_definitions_pb2 import (
21+
BoardDefinition,
22+
FpgaDefinition,
23+
)
2124

2225
# -- Boards definitions file name.
2326
BOARDS_JSONC = "boards.jsonc"
@@ -130,8 +133,7 @@ def __init__(
130133
self._project_definitions_dir,
131134
)
132135

133-
# -- Convert the board definition to BoardDefinition protos we keep
134-
# -- in this object.
136+
# -- Convert the board definition dicts to BoardDefinition protos.
135137
self.boards: Dict[str, BoardDefinition] = {}
136138
for board_id, definition_dict in boards_json.items():
137139
definition = proto_util.proto_from_json_dict(
@@ -149,34 +151,28 @@ def __init__(
149151
sys.exit(1)
150152

151153
# -- Read fpgas definitions.
152-
self.fpgas, self.custom_fpgas_ids = self._load_definitions(
154+
fpgas_json, self.custom_fpgas_ids = self._load_definitions(
153155
FPGAS_JSONC,
154156
self._package_definitions_dir,
155157
self._project_definitions_dir,
156158
)
157159

158-
# -- Validate fpgas definitions. Optional project custom definition
159-
# -- supersede apio standard definitions.
160-
for fpga_id, fpga_info in self.fpgas.items():
160+
# -- Convert the fpgas definition dicts to FpgasDefinition protos.
161+
self.fpgas: Dict[str, FpgaDefinition] = {}
162+
for fpga_id, definition_dict in fpgas_json.items():
163+
definition = proto_util.proto_from_json_dict(
164+
definition_dict,
165+
FpgaDefinition,
166+
f"Failed to parse fpga definition '{fpga_id}",
167+
)
168+
self.fpgas[fpga_id] = definition
169+
170+
# -- Validate fpgas definitions.
171+
for fpga_id, fpga_definition in self.fpgas.items():
161172
if not ID_FORMAT.match(fpga_id):
162173
cerror(f"FPGA id has an invalid format: {fpga_id}")
163174
sys.exit(1)
164-
try:
165-
validate(instance=fpga_info, schema=FPGA_SCHEMA)
166-
except ValidationError as e:
167-
cerror(f"Invalid fpga definition [{fpga_id}]: {e.message}")
168-
sys.exit(1)
169-
170-
# -- Expecting a params field for the specified architecture.
171-
params_pattern = re.compile(r".*-params$")
172-
actual_params = [
173-
key for key in fpga_info if params_pattern.match(key)
174-
]
175-
expected_params = [fpga_info["arch"] + "-params"]
176-
if actual_params != expected_params:
177-
cerror(f"Unexpected params {actual_params} in fpga {fpga_id}")
178-
sys.exit(1)
179-
part_num = fpga_info["part-num"]
175+
part_num = fpga_definition.part_num
180176
lc_part_num = part_num.lower().replace("/", "-")
181177
if fpga_id != lc_part_num and not fpga_id.startswith(
182178
lc_part_num + "-"

apio/managers/examples.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
from typing import Optional, List, Dict
1515
from apio.common.apio_console import cout, cstyle, cerror
1616
from apio.common.apio_styles import INFO, SUCCESS, EMPH3
17+
from apio.common.proto.apio_common_pb2 import ApioArch
1718
from apio.apio_context import ApioContext
1819
from apio.utils import util
1920

@@ -122,10 +123,10 @@ def get_examples_infos(self) -> List[ExampleInfo]:
122123
# -- Extract the fpga arch and part number, with "" as
123124
# -- default value if not found.
124125
fpga_id = board_definition.fpga_id
125-
fpga_info = definitions.fpgas[fpga_id]
126-
fpga_arch = fpga_info.get("arch", "")
127-
fpga_part_num = fpga_info.get("part-num", "")
128-
fpga_size = fpga_info.get("size", "")
126+
fpga_definition = definitions.fpgas[fpga_id]
127+
fpga_arch = ApioArch.Name(fpga_definition.arch)
128+
fpga_part_num = fpga_definition.part_num
129+
fpga_size = fpga_definition.size
129130

130131
# -- Append this example to the list.
131132
example_info = ExampleInfo(

0 commit comments

Comments
 (0)