blob: 78d955a2b96b34d6f4c55dd29ddbf7cf18c76153 [file] [log] [blame]
Sam Elliotte74c6292020-07-24 21:40:00 +01001# Copyright lowRISC contributors.
2# Licensed under the Apache License, Version 2.0, see LICENSE for details.
3# SPDX-License-Identifier: Apache-2.0
4"""This contains a class which is used to help generate `top_{name}.h` and
5`top_{name}.h`.
6"""
Srikrishna Iyer689981e2021-09-16 12:12:37 -07007from collections import OrderedDict, defaultdict
Rupert Swarbrick200d8b42021-03-08 12:32:11 +00008from typing import Dict, List, Optional, Tuple
Sam Elliott7931f2f2020-07-24 23:21:41 +01009
Sam Elliott66efff02020-07-24 22:35:10 +010010from mako.template import Template
Rupert Swarbrick200d8b42021-03-08 12:32:11 +000011from reggen.ip_block import IpBlock
12
Srikrishna Iyer689981e2021-09-16 12:12:37 -070013from .lib import Name, get_base_and_size
14
15C_FILE_EXTENSIONS = (".c", ".h", ".cc", ".inc")
16
Sam Elliotte74c6292020-07-24 21:40:00 +010017
Sam Elliotte74c6292020-07-24 21:40:00 +010018class MemoryRegion(object):
Rupert Swarbrick200d8b42021-03-08 12:32:11 +000019 def __init__(self, name: Name, base_addr: int, size_bytes: int):
20 assert isinstance(base_addr, int)
Sam Elliotte74c6292020-07-24 21:40:00 +010021 self.name = name
22 self.base_addr = base_addr
23 self.size_bytes = size_bytes
Rupert Swarbrick200d8b42021-03-08 12:32:11 +000024 self.size_words = (size_bytes + 3) // 4
Sam Elliotte74c6292020-07-24 21:40:00 +010025
26 def base_addr_name(self):
27 return self.name + Name(["base", "addr"])
28
Silvestrs Timofejevsa2d4a6a2020-10-08 10:47:54 +010029 def offset_name(self):
30 return self.name + Name(["offset"])
31
Sam Elliotte74c6292020-07-24 21:40:00 +010032 def size_bytes_name(self):
33 return self.name + Name(["size", "bytes"])
34
Silvestrs Timofejevsa2d4a6a2020-10-08 10:47:54 +010035 def size_words_name(self):
36 return self.name + Name(["size", "words"])
37
Sam Elliotte74c6292020-07-24 21:40:00 +010038
Sam Elliott66efff02020-07-24 22:35:10 +010039class CEnum(object):
40 def __init__(self, name):
41 self.name = name
42 self.enum_counter = 0
43 self.finalized = False
44
45 self.constants = []
46
47 def add_constant(self, constant_name, docstring=""):
48 assert not self.finalized
49
50 full_name = self.name + constant_name
51
52 value = self.enum_counter
53 self.enum_counter += 1
54
55 self.constants.append((full_name, value, docstring))
56
Sam Elliott7931f2f2020-07-24 23:21:41 +010057 return full_name
58
Sam Elliott66efff02020-07-24 22:35:10 +010059 def add_last_constant(self, docstring=""):
60 assert not self.finalized
61
62 full_name = self.name + Name(["last"])
63
64 _, last_val, _ = self.constants[-1]
65
66 self.constants.append((full_name, last_val, r"\internal " + docstring))
67 self.finalized = True
68
69 def render(self):
70 template = ("typedef enum ${enum.name.as_snake_case()} {\n"
71 "% for name, value, docstring in enum.constants:\n"
72 " ${name.as_c_enum()} = ${value}, /**< ${docstring} */\n"
73 "% endfor\n"
74 "} ${enum.name.as_c_type()};")
75 return Template(template).render(enum=self)
76
77
Sam Elliott7931f2f2020-07-24 23:21:41 +010078class CArrayMapping(object):
79 def __init__(self, name, output_type_name):
80 self.name = name
81 self.output_type_name = output_type_name
82
83 self.mapping = OrderedDict()
84
85 def add_entry(self, in_name, out_name):
86 self.mapping[in_name] = out_name
87
88 def render_declaration(self):
89 template = (
90 "extern const ${mapping.output_type_name.as_c_type()}\n"
91 " ${mapping.name.as_snake_case()}[${len(mapping.mapping)}];")
92 return Template(template).render(mapping=self)
93
94 def render_definition(self):
95 template = (
96 "const ${mapping.output_type_name.as_c_type()}\n"
97 " ${mapping.name.as_snake_case()}[${len(mapping.mapping)}] = {\n"
98 "% for in_name, out_name in mapping.mapping.items():\n"
99 " [${in_name.as_c_enum()}] = ${out_name.as_c_enum()},\n"
100 "% endfor\n"
101 "};\n")
102 return Template(template).render(mapping=self)
103
104
Rupert Swarbrick200d8b42021-03-08 12:32:11 +0000105class TopGenC:
106 def __init__(self, top_info, name_to_block: Dict[str, IpBlock]):
Sam Elliotte74c6292020-07-24 21:40:00 +0100107 self.top = top_info
Sam Elliott66efff02020-07-24 22:35:10 +0100108 self._top_name = Name(["top"]) + Name.from_snake_case(top_info["name"])
Rupert Swarbrick200d8b42021-03-08 12:32:11 +0000109 self._name_to_block = name_to_block
Sam Elliotte74c6292020-07-24 21:40:00 +0100110
Sam Elliottd1790472020-07-24 23:25:10 +0100111 # The .c file needs the .h file's relative path, store it here
112 self.header_path = None
113
Sam Elliott7931f2f2020-07-24 23:21:41 +0100114 self._init_plic_targets()
115 self._init_plic_mapping()
Sam Elliotta7b7b5f2020-07-24 23:46:36 +0100116 self._init_alert_mapping()
Sam Elliottfbb34ec2020-07-25 02:00:22 +0100117 self._init_pinmux_mapping()
Timothy Chen2fb27672022-09-09 12:20:00 -0700118 self._init_pad_mapping()
Sam Elliott1625b632020-08-17 15:08:43 +0100119 self._init_pwrmgr_wakeups()
Timothy Chend9d088b2020-09-25 13:14:09 -0700120 self._init_rstmgr_sw_rsts()
Timothy Chenf8726cd2020-09-24 14:05:37 -0700121 self._init_pwrmgr_reset_requests()
Sam Elliott9d7a1e32020-10-19 18:45:50 +0100122 self._init_clkmgr_clocks()
Alphan Ulusoy3c169942022-08-17 11:47:28 -0400123 self._init_mmio_region()
Sam Elliotta7b7b5f2020-07-24 23:46:36 +0100124
Rupert Swarbrick200d8b42021-03-08 12:32:11 +0000125 def devices(self) -> List[Tuple[Tuple[str, Optional[str]], MemoryRegion]]:
126 '''Return a list of MemoryRegion objects for devices on the bus
127
128 The list returned is pairs (full_if, region) where full_if is itself a
129 pair (inst_name, if_name). inst_name is the name of some IP block
130 instantiation. if_name is the name of the interface (may be None).
131 region is a MemoryRegion object representing the device.
132
133 '''
134 ret = [] # type: List[Tuple[Tuple[str, Optional[str]], MemoryRegion]]
Srikrishna Iyer689981e2021-09-16 12:12:37 -0700135 # TODO: This method is invoked in templates, as well as in the extended
136 # class TopGenCTest. We could refactor and optimize the implementation
137 # a bit.
138 self.device_regions = defaultdict(dict)
Rupert Swarbrick200d8b42021-03-08 12:32:11 +0000139 for inst in self.top['module']:
140 block = self._name_to_block[inst['type']]
141 for if_name, rb in block.reg_blocks.items():
142 full_if = (inst['name'], if_name)
143 full_if_name = Name.from_snake_case(full_if[0])
144 if if_name is not None:
145 full_if_name += Name.from_snake_case(if_name)
146
147 name = self._top_name + full_if_name
148 base, size = get_base_and_size(self._name_to_block,
149 inst, if_name)
150
151 region = MemoryRegion(name, base, size)
Srikrishna Iyer689981e2021-09-16 12:12:37 -0700152 self.device_regions[inst['name']].update({if_name: region})
Rupert Swarbrick200d8b42021-03-08 12:32:11 +0000153 ret.append((full_if, region))
154
155 return ret
Sam Elliotta7b7b5f2020-07-24 23:46:36 +0100156
157 def memories(self):
Michael Schaffner02e982f2021-07-09 17:40:34 -0700158 ret = []
159 for m in self.top["memory"]:
160 ret.append((m["name"],
161 MemoryRegion(self._top_name +
162 Name.from_snake_case(m["name"]),
163 int(m["base_addr"], 0),
164 int(m["size"], 0))))
165
166 for inst in self.top['module']:
167 if "memory" in inst:
168 for if_name, val in inst["memory"].items():
169 base, size = get_base_and_size(self._name_to_block,
170 inst, if_name)
171
172 name = self._top_name + Name.from_snake_case(val["label"])
173 region = MemoryRegion(name, base, size)
174 ret.append((val["label"], region))
175
176 return ret
Sam Elliott7931f2f2020-07-24 23:21:41 +0100177
178 def _init_plic_targets(self):
179 enum = CEnum(self._top_name + Name(["plic", "target"]))
180
181 for core_id in range(int(self.top["num_cores"])):
182 enum.add_constant(Name(["ibex", str(core_id)]),
183 docstring="Ibex Core {}".format(core_id))
184
185 enum.add_last_constant("Final PLIC target")
186
187 self.plic_targets = enum
188
189 def _init_plic_mapping(self):
190 """We eventually want to generate a mapping from interrupt id to the
191 source peripheral.
192
Sam Elliotta7b7b5f2020-07-24 23:46:36 +0100193 In order to do so, we generate two enums (one for interrupts, one for
194 sources), and store the generated names in a dictionary that represents
195 the mapping.
Sam Elliott7931f2f2020-07-24 23:21:41 +0100196
Sam Elliotta7b7b5f2020-07-24 23:46:36 +0100197 PLIC Interrupt ID 0 corresponds to no interrupt, and so no peripheral,
Sam Elliott7931f2f2020-07-24 23:21:41 +0100198 so we encode that in the enum as "unknown".
199
200 The interrupts have to be added in order, with "none" first, to ensure
201 that they get the correct mapping to their PLIC id, which is used for
202 addressing the right registers and bits.
203 """
204 sources = CEnum(self._top_name + Name(["plic", "peripheral"]))
205 interrupts = CEnum(self._top_name + Name(["plic", "irq", "id"]))
206 plic_mapping = CArrayMapping(
207 self._top_name + Name(["plic", "interrupt", "for", "peripheral"]),
208 sources.name)
209
210 unknown_source = sources.add_constant(Name(["unknown"]),
211 docstring="Unknown Peripheral")
212 none_irq_id = interrupts.add_constant(Name(["none"]),
213 docstring="No Interrupt")
214 plic_mapping.add_entry(none_irq_id, unknown_source)
215
216 # When we generate the `interrupts` enum, the only info we have about
217 # the source is the module name. We'll use `source_name_map` to map a
218 # short module name to the full name object used for the enum constant.
219 source_name_map = {}
220
221 for name in self.top["interrupt_module"]:
222 source_name = sources.add_constant(Name.from_snake_case(name),
223 docstring=name)
224 source_name_map[name] = source_name
225
226 sources.add_last_constant("Final PLIC peripheral")
227
Srikrishna Iyer689981e2021-09-16 12:12:37 -0700228 # Maintain a list of instance-specific IRQs by instance name.
229 self.device_irqs = defaultdict(list)
Sam Elliott7931f2f2020-07-24 23:21:41 +0100230 for intr in self.top["interrupt"]:
231 # Some interrupts are multiple bits wide. Here we deal with that by
232 # adding a bit-index suffix
233 if "width" in intr and int(intr["width"]) != 1:
234 for i in range(int(intr["width"])):
Weicai Yang53b0d4d2020-11-30 15:28:33 -0800235 name = Name.from_snake_case(intr["name"]) + Name([str(i)])
Sam Elliott7931f2f2020-07-24 23:21:41 +0100236 irq_id = interrupts.add_constant(name,
237 docstring="{} {}".format(
238 intr["name"], i))
239 source_name = source_name_map[intr["module_name"]]
240 plic_mapping.add_entry(irq_id, source_name)
Srikrishna Iyer689981e2021-09-16 12:12:37 -0700241 self.device_irqs[intr["module_name"]].append(intr["name"] +
242 str(i))
Sam Elliott7931f2f2020-07-24 23:21:41 +0100243 else:
244 name = Name.from_snake_case(intr["name"])
245 irq_id = interrupts.add_constant(name, docstring=intr["name"])
246 source_name = source_name_map[intr["module_name"]]
247 plic_mapping.add_entry(irq_id, source_name)
Srikrishna Iyer689981e2021-09-16 12:12:37 -0700248 self.device_irqs[intr["module_name"]].append(intr["name"])
Sam Elliott7931f2f2020-07-24 23:21:41 +0100249
250 interrupts.add_last_constant("The Last Valid Interrupt ID.")
251
252 self.plic_sources = sources
253 self.plic_interrupts = interrupts
254 self.plic_mapping = plic_mapping
255
Sam Elliotta7b7b5f2020-07-24 23:46:36 +0100256 def _init_alert_mapping(self):
257 """We eventually want to generate a mapping from alert id to the source
258 peripheral.
Sam Elliotte74c6292020-07-24 21:40:00 +0100259
Sam Elliotta7b7b5f2020-07-24 23:46:36 +0100260 In order to do so, we generate two enums (one for alerts, one for
261 sources), and store the generated names in a dictionary that represents
262 the mapping.
263
264 Alert Handler has no concept of "no alert", unlike the PLIC.
265
266 The alerts have to be added in order, to ensure that they get the
267 correct mapping to their alert id, which is used for addressing the
268 right registers and bits.
269 """
270 sources = CEnum(self._top_name + Name(["alert", "peripheral"]))
271 alerts = CEnum(self._top_name + Name(["alert", "id"]))
272 alert_mapping = CArrayMapping(
273 self._top_name + Name(["alert", "for", "peripheral"]),
274 sources.name)
275
276 # When we generate the `alerts` enum, the only info we have about the
277 # source is the module name. We'll use `source_name_map` to map a short
278 # module name to the full name object used for the enum constant.
279 source_name_map = {}
280
281 for name in self.top["alert_module"]:
282 source_name = sources.add_constant(Name.from_snake_case(name),
283 docstring=name)
284 source_name_map[name] = source_name
285
286 sources.add_last_constant("Final Alert peripheral")
287
Cindy Chen21447a22022-04-18 17:55:25 -0700288 self.device_alerts = defaultdict(list)
Sam Elliotta7b7b5f2020-07-24 23:46:36 +0100289 for alert in self.top["alert"]:
290 if "width" in alert and int(alert["width"]) != 1:
291 for i in range(int(alert["width"])):
Weicai Yang53b0d4d2020-11-30 15:28:33 -0800292 name = Name.from_snake_case(alert["name"]) + Name([str(i)])
293 irq_id = alerts.add_constant(name,
294 docstring="{} {}".format(
295 alert["name"], i))
Sam Elliotta7b7b5f2020-07-24 23:46:36 +0100296 source_name = source_name_map[alert["module_name"]]
297 alert_mapping.add_entry(irq_id, source_name)
Cindy Chen21447a22022-04-18 17:55:25 -0700298 self.device_alerts[alert["module_name"]].append(alert["name"] +
299 str(i))
Sam Elliotta7b7b5f2020-07-24 23:46:36 +0100300 else:
301 name = Name.from_snake_case(alert["name"])
302 alert_id = alerts.add_constant(name, docstring=alert["name"])
303 source_name = source_name_map[alert["module_name"]]
304 alert_mapping.add_entry(alert_id, source_name)
Cindy Chen21447a22022-04-18 17:55:25 -0700305 self.device_alerts[alert["module_name"]].append(alert["name"])
Sam Elliotta7b7b5f2020-07-24 23:46:36 +0100306
307 alerts.add_last_constant("The Last Valid Alert ID.")
308
309 self.alert_sources = sources
310 self.alert_alerts = alerts
311 self.alert_mapping = alert_mapping
Sam Elliottfbb34ec2020-07-25 02:00:22 +0100312
313 def _init_pinmux_mapping(self):
314 """Generate C enums for addressing pinmux registers and in/out selects.
315
Michael Schaffnerb5b8eba2021-02-09 20:07:04 -0800316 Inputs/outputs are connected in the order the modules are listed in
317 the hjson under the "mio_modules" key. For each module, the corresponding
318 inouts are connected first, followed by either the inputs or the outputs.
Sam Elliottfbb34ec2020-07-25 02:00:22 +0100319
320 Inputs:
321 - Peripheral chooses register field (pinmux_peripheral_in)
322 - Insel chooses MIO input (pinmux_insel)
323
324 Outputs:
325 - MIO chooses register field (pinmux_mio_out)
326 - Outsel chooses peripheral output (pinmux_outsel)
327
328 Insel and outsel have some special values which are captured here too.
329 """
Michael Schaffner74c4ff22021-03-30 15:43:46 -0700330 pinmux_info = self.top['pinmux']
331 pinout_info = self.top['pinout']
Sam Elliottfbb34ec2020-07-25 02:00:22 +0100332
333 # Peripheral Inputs
334 peripheral_in = CEnum(self._top_name +
Michael Schaffner74c4ff22021-03-30 15:43:46 -0700335 Name(['pinmux', 'peripheral', 'in']))
336 i = 0
337 for sig in pinmux_info['ios']:
338 if sig['connection'] == 'muxed' and sig['type'] in ['inout', 'input']:
339 index = Name([str(sig['idx'])]) if sig['idx'] != -1 else Name([])
340 name = Name.from_snake_case(sig['name']) + index
341 peripheral_in.add_constant(name, docstring='Peripheral Input {}'.format(i))
342 i += 1
343
344 peripheral_in.add_last_constant('Last valid peripheral input')
Sam Elliottfbb34ec2020-07-25 02:00:22 +0100345
346 # Pinmux Input Selects
Michael Schaffner74c4ff22021-03-30 15:43:46 -0700347 insel = CEnum(self._top_name + Name(['pinmux', 'insel']))
348 insel.add_constant(Name(['constant', 'zero']),
349 docstring='Tie constantly to zero')
350 insel.add_constant(Name(['constant', 'one']),
351 docstring='Tie constantly to one')
352 i = 0
353 for pad in pinout_info['pads']:
354 if pad['connection'] == 'muxed':
355 insel.add_constant(Name([pad['name']]),
356 docstring='MIO Pad {}'.format(i))
357 i += 1
358 insel.add_last_constant('Last valid insel value')
Sam Elliottfbb34ec2020-07-25 02:00:22 +0100359
360 # MIO Outputs
Michael Schaffner74c4ff22021-03-30 15:43:46 -0700361 mio_out = CEnum(self._top_name + Name(['pinmux', 'mio', 'out']))
362 i = 0
363 for pad in pinout_info['pads']:
364 if pad['connection'] == 'muxed':
365 mio_out.add_constant(Name.from_snake_case(pad['name']),
366 docstring='MIO Pad {}'.format(i))
367 i += 1
368 mio_out.add_last_constant('Last valid mio output')
Sam Elliottfbb34ec2020-07-25 02:00:22 +0100369
370 # Pinmux Output Selects
Michael Schaffner74c4ff22021-03-30 15:43:46 -0700371 outsel = CEnum(self._top_name + Name(['pinmux', 'outsel']))
372 outsel.add_constant(Name(['constant', 'zero']),
373 docstring='Tie constantly to zero')
374 outsel.add_constant(Name(['constant', 'one']),
375 docstring='Tie constantly to one')
376 outsel.add_constant(Name(['constant', 'high', 'z']),
377 docstring='Tie constantly to high-Z')
378 i = 0
379 for sig in pinmux_info['ios']:
380 if sig['connection'] == 'muxed' and sig['type'] in ['inout', 'output']:
381 index = Name([str(sig['idx'])]) if sig['idx'] != -1 else Name([])
382 name = Name.from_snake_case(sig['name']) + index
383 outsel.add_constant(name, docstring='Peripheral Output {}'.format(i))
384 i += 1
385
386 outsel.add_last_constant('Last valid outsel value')
Sam Elliottfbb34ec2020-07-25 02:00:22 +0100387
388 self.pinmux_peripheral_in = peripheral_in
389 self.pinmux_insel = insel
390 self.pinmux_mio_out = mio_out
391 self.pinmux_outsel = outsel
Sam Elliott1625b632020-08-17 15:08:43 +0100392
Timothy Chen2fb27672022-09-09 12:20:00 -0700393 def _init_pad_mapping(self):
394 """Generate C enums for order of MIO and DIO pads.
395
396 These are needed to configure pad specific configurations such as
397 slew rate and other flags.
398 """
399 direct_enum = CEnum(self._top_name +
400 Name(["direct", "pads"]))
401
402 muxed_enum = CEnum(self._top_name +
403 Name(["muxed", "pads"]))
404
405 pads_info = self.top['pinout']['pads']
406 muxed = [pad['name'] for pad in pads_info if pad['connection'] == 'muxed']
407
408 # The logic here follows the sequence done in toplevel_pkg.sv.tpl.
409 # The direct pads do not enumerate directly from the pinout like the muxed
410 # ios. Instead it follows a direction from the pinmux perspective.
411 pads_info = self.top['pinmux']['ios']
412 direct = [pad for pad in pads_info if pad['connection'] != 'muxed']
413
414 for pad in (direct):
415 name = f"{pad['name']}"
416 if pad['width'] > 1:
417 name = f"{name}{pad['idx']}"
418
419 direct_enum.add_constant(
420 Name.from_snake_case(name))
421 direct_enum.add_last_constant("Last valid direct pad")
422
423 for pad in (muxed):
424 muxed_enum.add_constant(
425 Name.from_snake_case(pad))
426 muxed_enum.add_last_constant("Last valid muxed pad")
427
428 self.direct_pads = direct_enum
429 self.muxed_pads = muxed_enum
430
431
Sam Elliott1625b632020-08-17 15:08:43 +0100432 def _init_pwrmgr_wakeups(self):
Weicai Yang53b0d4d2020-11-30 15:28:33 -0800433 enum = CEnum(self._top_name +
434 Name(["power", "manager", "wake", "ups"]))
Sam Elliott1625b632020-08-17 15:08:43 +0100435
436 for signal in self.top["wakeups"]:
Weicai Yang53b0d4d2020-11-30 15:28:33 -0800437 enum.add_constant(
438 Name.from_snake_case(signal["module"]) +
439 Name.from_snake_case(signal["name"]))
Sam Elliott1625b632020-08-17 15:08:43 +0100440
441 enum.add_last_constant("Last valid pwrmgr wakeup signal")
442
443 self.pwrmgr_wakeups = enum
Timothy Chend9d088b2020-09-25 13:14:09 -0700444
445 # Enumerates the positions of all software controllable resets
446 def _init_rstmgr_sw_rsts(self):
Timothy Chen7c3de6e2021-07-19 16:46:45 -0700447 sw_rsts = self.top['resets'].get_sw_resets()
Timothy Chend9d088b2020-09-25 13:14:09 -0700448
Weicai Yang53b0d4d2020-11-30 15:28:33 -0800449 enum = CEnum(self._top_name +
450 Name(["reset", "manager", "sw", "resets"]))
Timothy Chend9d088b2020-09-25 13:14:09 -0700451
452 for rst in sw_rsts:
Timothy Chen7c3de6e2021-07-19 16:46:45 -0700453 enum.add_constant(Name.from_snake_case(rst))
Timothy Chend9d088b2020-09-25 13:14:09 -0700454
455 enum.add_last_constant("Last valid rstmgr software reset request")
456
457 self.rstmgr_sw_rsts = enum
Timothy Chenf8726cd2020-09-24 14:05:37 -0700458
459 def _init_pwrmgr_reset_requests(self):
Weicai Yang53b0d4d2020-11-30 15:28:33 -0800460 enum = CEnum(self._top_name +
461 Name(["power", "manager", "reset", "requests"]))
Timothy Chenf8726cd2020-09-24 14:05:37 -0700462
463 for signal in self.top["reset_requests"]:
Weicai Yang53b0d4d2020-11-30 15:28:33 -0800464 enum.add_constant(
465 Name.from_snake_case(signal["module"]) +
466 Name.from_snake_case(signal["name"]))
Timothy Chenf8726cd2020-09-24 14:05:37 -0700467
468 enum.add_last_constant("Last valid pwrmgr reset_request signal")
469
470 self.pwrmgr_reset_requests = enum
Sam Elliott9d7a1e32020-10-19 18:45:50 +0100471
472 def _init_clkmgr_clocks(self):
473 """
474 Creates CEnums for accessing the software-controlled clocks in the
475 design.
476
477 The logic here matches the logic in topgen.py in how it instantiates the
478 clock manager with the described clocks.
479
480 We differentiate "gateable" clocks and "hintable" clocks because the
481 clock manager has separate register interfaces for each group.
482 """
Rupert Swarbrick127b1092021-07-16 17:10:39 +0100483 clocks = self.top['clocks']
Sam Elliott9d7a1e32020-10-19 18:45:50 +0100484
Sam Elliott9d7a1e32020-10-19 18:45:50 +0100485 gateable_clocks = CEnum(self._top_name + Name(["gateable", "clocks"]))
486 hintable_clocks = CEnum(self._top_name + Name(["hintable", "clocks"]))
487
Rupert Swarbrick0c9cf5c2021-07-19 11:55:18 +0100488 c2g = clocks.make_clock_to_group()
489 by_type = clocks.typed_clocks()
Sam Elliott9d7a1e32020-10-19 18:45:50 +0100490
Rupert Swarbrick0c9cf5c2021-07-19 11:55:18 +0100491 for name in by_type.sw_clks.keys():
492 # All these clocks start with `clk_` which is redundant.
493 clock_name = Name.from_snake_case(name).remove_part("clk")
494 docstring = "Clock {} in group {}".format(name, c2g[name].name)
495 gateable_clocks.add_constant(clock_name, docstring)
Sam Elliott9d7a1e32020-10-19 18:45:50 +0100496 gateable_clocks.add_last_constant("Last Valid Gateable Clock")
Rupert Swarbrick0c9cf5c2021-07-19 11:55:18 +0100497
498 for name in by_type.hint_clks.keys():
499 # All these clocks start with `clk_` which is redundant.
500 clock_name = Name.from_snake_case(name).remove_part("clk")
501 docstring = "Clock {} in group {}".format(name, c2g[name].name)
502 hintable_clocks.add_constant(clock_name, docstring)
Sam Elliott9d7a1e32020-10-19 18:45:50 +0100503 hintable_clocks.add_last_constant("Last Valid Hintable Clock")
504
505 self.clkmgr_gateable_clocks = gateable_clocks
506 self.clkmgr_hintable_clocks = hintable_clocks
Alphan Ulusoy3c169942022-08-17 11:47:28 -0400507
508 def _init_mmio_region(self):
509 """
510 Computes the bounds of the MMIO region.
511
512 MMIO region excludes any memory that is separate from the module configuration
513 space, i.e. ROM, main SRAM, and flash are excluded but retention SRAM,
514 spi_device memory, or usbdev memory are included.
515 """
516 memories = [region.base_addr for (_, region) in self.memories()]
517 # TODO(#14345): Remove the hardcoded "rv_dm" name check below.
518 regions = [
519 region for ((dev_name, _), region) in self.devices()
520 if region.base_addr not in memories and dev_name != "rv_dm"
521 ]
522 # Note: The memory interface of the retention RAM is in the MMIO address space,
523 # which we prefer since it reduces the number of ePMP regions we need.
524 mmio = range(min([r.base_addr for r in regions]),
525 max([r.base_addr + r.size_bytes for r in regions]))
526 self.mmio = MemoryRegion(self._top_name + Name(["mmio"]), mmio.start,
527 mmio.stop - mmio.start)