Coverage for hdl_registers/register_vhdl_generator.py: 99%
113 statements
« prev ^ index » next coverage.py v6.5.0, created at 2023-01-29 22:03 +0000
« prev ^ index » next coverage.py v6.5.0, created at 2023-01-29 22:03 +0000
1# --------------------------------------------------------------------------------------------------
2# Copyright (c) Lukas Vik. All rights reserved.
3#
4# This file is part of the hdl_registers project, a HDL register generator fast enough to be run
5# in real time.
6# https://hdl-registers.com
7# https://gitlab.com/hdl_registers/hdl_registers
8# --------------------------------------------------------------------------------------------------
10# Local folder libraries
11from .register import Register
12from .register_array import RegisterArray
13from .register_code_generator import RegisterCodeGenerator
16class RegisterVhdlGenerator(RegisterCodeGenerator):
17 """
18 Generate a VHDL package with register information.
19 """
21 def __init__(self, module_name, generated_info):
22 """
23 Arguments:
24 module_name (str): The name of the register map.
25 generated_info (list(str)): Will be placed in the file headers.
26 """
27 self.module_name = module_name
28 self.generated_info = generated_info
30 @staticmethod
31 def _comment(comment, indentation=0):
32 indent = " " * indentation
33 return f"{indent}-- {comment}\n"
35 def _header(self):
36 return "".join([self._comment(header_line) for header_line in self.generated_info])
38 def _register_name(self, register, register_array=None):
39 if register_array is None:
40 return f"{self.module_name}_{register.name}"
41 return f"{self.module_name}_{register_array.name}_{register.name}"
43 def _register_function_signature(self, register, register_array):
44 return (
45 "function "
46 f"{self._register_name(register, register_array)}(array_index : natural) return natural"
47 )
49 def _register_indexes(self, register_objects):
50 vhdl = ""
51 for register, register_array in self._iterate_registers(register_objects):
52 if register_array is None:
53 vhdl += (
54 f" constant {self._register_name(register)} : natural := {register.index};\n"
55 )
56 else:
57 vhdl += f" {self._register_function_signature(register, register_array)};\n"
58 if vhdl:
59 vhdl += "\n"
61 return vhdl
63 def _array_length_constant_name(self, register_array):
64 return f"{self.module_name}_{register_array.name}_array_length"
66 def _array_constants(self, register_objects):
67 vhdl = ""
68 for register_object in register_objects:
69 if isinstance(register_object, RegisterArray):
70 constant = self._array_length_constant_name(register_object)
71 vhdl += f" constant {constant} : natural := {register_object.length};\n"
72 if vhdl:
73 vhdl += "\n"
75 return vhdl
77 def _register_map(self, register_objects):
78 if not register_objects:
79 # It is possible that we have constants but no registers
80 return ""
82 map_name = f"{self.module_name}_reg_map"
83 range_name = f"{self.module_name}_reg_range"
85 last_index = register_objects[-1].index
86 vhdl = f"""\
87 -- Declare register map constants here, but define them in body.
88 -- This is done so that functions have been elaborated when they are called.
89 subtype {range_name} is natural range 0 to {last_index};
90 constant {map_name} : reg_definition_vec_t({range_name});
92 subtype {self.module_name}_regs_t is reg_vec_t({range_name});
93 constant {self.module_name}_regs_init : {self.module_name}_regs_t;
95 subtype {self.module_name}_reg_was_accessed_t is std_ulogic_vector({range_name});
97"""
99 return vhdl
101 def _register_map_body(self, register_objects):
102 if not register_objects:
103 # It is possible that we have constants but no registers
104 return ""
106 map_name = f"{self.module_name}_reg_map"
107 range_name = f"{self.module_name}_reg_range"
109 register_definitions = []
110 default_values = []
111 vhdl_array_index = 0
112 for register_object in register_objects:
113 if isinstance(register_object, Register):
114 idx = self._register_name(register_object)
115 opening = f"{vhdl_array_index} => "
117 register_definitions.append(
118 f"{opening}(idx => {idx}, reg_type => {register_object.mode})"
119 )
120 default_values.append(f'{opening}"{register_object.default_value:032b}"')
122 vhdl_array_index = vhdl_array_index + 1
123 else:
124 for array_index in range(register_object.length):
125 for register in register_object.registers:
126 idx = f"{self._register_name(register, register_object)}({array_index})"
127 opening = f"{vhdl_array_index} => "
129 register_definitions.append(
130 f"{opening}(idx => {idx}, reg_type => {register.mode})"
131 )
132 default_values.append(f'{opening}"{register.default_value:032b}"')
134 vhdl_array_index = vhdl_array_index + 1
136 array_element_separator = ",\n "
137 vhdl = f"""\
138 constant {map_name} : reg_definition_vec_t({range_name}) := (
139 {array_element_separator.join(register_definitions)}
140 );
142 constant {self.module_name}_regs_init : {self.module_name}_regs_t := (
143 {array_element_separator.join(default_values)}
144 );
146"""
148 return vhdl
150 def _register_fields(self, register_objects):
151 vhdl = ""
152 for register, register_array in self._iterate_registers(register_objects):
153 for field in register.fields:
154 name = f"{self._register_name(register, register_array)}_{field.name}"
156 if field.width == 1:
157 vhdl += f" constant {name} : natural := {field.base_index};\n"
158 else:
159 vhdl += f"""\
160 subtype {name} is natural range {field.width + field.base_index - 1} downto {field.base_index};
161 constant {name}_width : positive := {field.width};
162 subtype {name}_t is {field.field_type.vhdl_typedef(bit_width=field.width)};
163"""
165 if register.fields:
166 vhdl += "\n"
168 return vhdl
170 def _array_index_functions(self, register_objects):
171 vhdl = ""
172 for register_object in register_objects:
173 if isinstance(register_object, RegisterArray):
174 num_registers = len(register_object.registers)
175 array_length = self._array_length_constant_name(register_object)
176 for register in register_object.registers:
177 vhdl += f"""\
178 {self._register_function_signature(register, register_object)} is
179 begin
180 assert array_index < {array_length}
181 report "Array index out of bounds: " & natural'image(array_index)
182 severity failure;
183 return {register_object.base_index} + array_index * {num_registers} + {register.index};
184 end function;
186"""
188 return vhdl
190 def _constants(self, constants):
191 vhdl = ""
192 for constant in constants:
193 if constant.is_boolean:
194 type_name = "boolean"
195 value = str(constant.value).lower()
196 elif constant.is_integer:
197 type_name = "integer"
198 value = constant.value
199 elif constant.is_float:
200 type_name = "real"
201 value = constant.value
202 else:
203 raise ValueError(f"Got unexpected constant type. {constant}")
205 vhdl += (
206 " constant "
207 f"{self.module_name}_constant_{constant.name} : {type_name} := {value};\n"
208 )
209 if vhdl:
210 vhdl += "\n"
212 return vhdl
214 def get_package(self, register_objects, constants):
215 """
216 Get a complete VHDL package with register and constant infomation.
218 Arguments:
219 register_objects (list): Register arrays and registers to be included.
220 constants (list(Constant)): Constants to be included.
222 Returns:
223 str: VHDL code.
224 """
225 pkg_name = f"{self.module_name}_regs_pkg"
227 vhdl = f"""\
228{self._header()}
229library ieee;
230use ieee.std_logic_1164.all;
231use ieee.numeric_std.all;
232use ieee.fixed_pkg.all;
234library reg_file;
235use reg_file.reg_file_pkg.all;
238package {pkg_name} is
240{self._register_indexes(register_objects)}\
241{self._array_constants(register_objects)}\
242{self._register_map(register_objects)}\
243{self._register_fields(register_objects)}\
244{self._constants(constants)}\
245end package;
247package body {pkg_name} is
249{self._array_index_functions(register_objects)}\
250{self._register_map_body(register_objects)}\
251end package body;
252"""
254 return vhdl