Cerata
A library to generate structural hardware designs
declaration.cc
1 // Copyright 2018-2019 Delft University of Technology
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "cerata/vhdl/declaration.h"
16 
17 #include <memory>
18 #include <string>
19 #include <vector>
20 
21 #include "cerata/node.h"
22 #include "cerata/expression.h"
23 #include "cerata/parameter.h"
24 #include "cerata/type.h"
25 #include "cerata/graph.h"
26 #include "cerata/vhdl/identifier.h"
27 #include "cerata/vhdl/vhdl_types.h"
28 #include "cerata/vhdl/vhdl.h"
29 
30 namespace cerata::vhdl {
31 
32 static std::string GenerateTypeDecl(const Type &type, std::optional<Node *> multiplier = std::nullopt) {
33  std::shared_ptr<Node> mult;
34  if (multiplier) {
35  mult = multiplier.value()->shared_from_this();
36  }
37  switch (type.id()) {
38  default: {
39  if (!multiplier) {
40  return "std_logic";
41  } else {
42  return "std_logic_vector(" + ToUpper((mult - 1)->ToString()) + " downto 0)";
43  }
44  }
45  case Type::VECTOR: {
46  auto &vec = dynamic_cast<const Vector &>(type);
47  auto width = vec.width().value()->shared_from_this();
48  if (!multiplier) {
49  auto expr = width->shared_from_this() - 1;
50  return "std_logic_vector(" + ToUpper(expr->ToString()) + " downto 0)";
51  } else {
52  auto expr = mult * width - 1;
53  return "std_logic_vector(" + ToUpper(expr->ToString()) + " downto 0)";
54  }
55  }
56  case Type::RECORD: {
57  auto record = dynamic_cast<const Record &>(type);
58  return record.name();
59  }
60  case Type::INTEGER: {
61  return "integer";
62  }
63  case Type::STRING: {
64  return "string";
65  }
66  case Type::BOOLEAN: {
67  return "boolean";
68  }
69  }
70 }
71 
72 Block Decl::Generate(const Parameter &par, int depth) {
73  Block ret(depth);
74  Line l;
75  l << ToUpper(par.name()) << " : " << GenerateTypeDecl(*par.type());
76  Node *val = par.value();
77  auto val_str = val->ToString();
78  if (par.type()->Is(Type::STRING)) {
79  val_str = "\"" + val_str + "\"";
80  }
81  l << " := " << val_str;
82  ret << l;
83  return ret;
84 }
85 
86 Block Decl::Generate(const Port &port, int depth) {
87  Block ret(depth);
88  // Filter out abstract types and flatten
89  auto flat_types = FilterForVHDL(Flatten(port.type()));
90  for (const auto &ft : flat_types) {
91  Line l;
92  auto port_name_prefix = port.name();
93  l << ft.name(NamePart(port_name_prefix, true)) << " : ";
94  if (ft.reverse_) {
95  l << ToString(Term::Reverse(port.dir())) + " ";
96  } else {
97  l << ToString(port.dir()) + " ";
98  }
99  l << GenerateTypeDecl(*ft.type_);
100  ret << l;
101  }
102  return ret;
103 }
104 
105 Block Decl::Generate(const Signal &sig, int depth) {
106  Block ret(depth);
107  // Flatten the type of this port
108  auto flat_types = FilterForVHDL(Flatten(sig.type()));
109 
110  // Generate signal decl for every flat type
111  for (const auto &ft : flat_types) {
112  Line l;
113  auto sig_name_prefix = sig.name();
114  l << "signal " + ft.name(NamePart(sig_name_prefix, true)) << " : ";
115  if (ft.type_->meta.count(meta::FORCE_VECTOR)) {
116  l << GenerateTypeDecl(*ft.type_, intl(1).get()) + ";";
117  } else {
118  l << GenerateTypeDecl(*ft.type_) + ";";
119  }
120  ret << l;
121  }
122  return ret;
123 }
124 
126  Block ret(depth);
127  // Flatten the type of this port
128  auto flat_types = FilterForVHDL(Flatten(port_array.type()));
129 
130  for (const auto &ft : flat_types) {
131  Line l;
132  auto port_name_prefix = port_array.name();
133  l << ft.name(NamePart(port_name_prefix, true)) << " : ";
134  if (ft.reverse_) {
135  l << ToString(Term::Reverse(port_array.dir())) + " ";
136  } else {
137  l << ToString(port_array.dir()) + " ";
138  }
139  l << GenerateTypeDecl(*ft.type_, port_array.size());
140  ret << l;
141  }
142  return ret;
143 }
144 
145 Block Decl::Generate(const SignalArray &sig_array, int depth) {
146  Block ret(depth);
147  // Flatten the type of this port
148  auto flat_types = FilterForVHDL(Flatten(sig_array.type()));
149 
150  for (const auto &ft : flat_types) {
151  Line l;
152  auto port_name_prefix = sig_array.name();
153  l << "signal " + ft.name(NamePart(port_name_prefix, true)) << " : ";
154  l << GenerateTypeDecl(*ft.type_, sig_array.size()) + ";";
155  ret << l;
156  }
157  return ret;
158 }
159 
160 MultiBlock Decl::Generate(const Component &comp, bool entity, int indent) {
161  MultiBlock ret(indent);
162 
163  if (entity) {
164  ret.indent = 0;
165  }
166 
167  // Header
168  Block h(ret.indent), f(ret.indent);
169  Line hl, fl;
170  if (entity) {
171  hl << "entity " + comp.name() + " is";
172  } else {
173  hl << "component " + comp.name() + " is";
174  }
175  h << hl;
176  ret << h;
177 
178  // Generics
179  std::vector<Parameter *> parameters = comp.GetAll<Parameter>();
180  if (!parameters.empty()) {
181  Block gdh(ret.indent + 1);
182  Block gd(ret.indent + 2);
183  Block gdf(ret.indent + 1);
184  Line gh, gf;
185  gh << "generic (";
186  gdh << gh;
187  for (Parameter *gen : parameters) {
188  auto g = Decl::Generate(*gen, ret.indent + 2);
189  if (gen != parameters.back()) {
190  g << ";";
191  } else {
192  g <<= ";";
193  }
194  gd << g;
195  }
196  gf << ");";
197  gdf << gf;
198  ret << gdh << gd << gdf;
199  }
200 
201  auto ports = comp.GetAll<Port>();
202  auto array_ports = comp.GetAll<PortArray>();
203  if (!ports.empty() || !array_ports.empty()) {
204  Block pdh(ret.indent + 1);
205  Block pd(ret.indent + 2);
206  Block pdf(ret.indent + 1);
207  Line ph, pf;
208  ph << "port (";
209  pdh << ph;
210  // Process ports
211  for (const auto &port : ports) {
212  auto g = Decl::Generate(*port, ret.indent + 2);
213  if (port != ports.back() || !array_ports.empty()) {
214  g << ";";
215  } else {
216  g <<= ";";
217  }
218  pd << g;
219  }
220  // Process array ports
221  for (const auto &array_port : array_ports) {
222  auto g = Decl::Generate(*array_port, ret.indent + 2);
223  if (array_port != array_ports.back()) {
224  g << ";";
225  } else {
226  g <<= ";";
227  }
228  pd << g;
229  }
230  pf << ");";
231  pdf << pf;
232  ret << pdh << pd << pdf;
233  }
234 
235  if (entity) {
236  fl << "end entity;";
237  } else {
238  fl << "end component;";
239  }
240 
241  f << fl;
242 
243  ret << f;
244 
245  return ret;
246 }
247 
248 } // namespace cerata::vhdl
cerata::Type::RECORD
@ RECORD
? | ? | Yes
Definition: type.h:77
cerata::NodeArray::type
Type * type() const
Return the type of the nodes in the NodeArray.
Definition: array.h:50
cerata::Component
A Component graph.
Definition: graph.h:158
cerata::Type::BOOLEAN
@ BOOLEAN
No | No | No.
Definition: type.h:75
cerata::Graph::GetAll
std::vector< T * > GetAll() const
Get all objects of a specific type.
Definition: graph.h:63
cerata::SignalArray
An array of signal nodes.
Definition: array.h:100
cerata::vhdl::MultiBlock
A structure to hold multiple blocks.
Definition: block.h:77
cerata::Parameter::value
Node * value() const
Return the value node.
Definition: parameter.cc:68
cerata::Signal
A Signal Node.
Definition: signal.h:30
cerata::vhdl::Line
A line of code.
Definition: block.h:25
cerata::Node
A node.
Definition: node.h:42
cerata::NamePart
Convenience struct to generate names in parts.
Definition: flattype.h:40
cerata::vhdl::MultiBlock::indent
int indent
Indent level.
Definition: block.h:85
cerata::Type::Is
bool Is(ID type_id) const
Return true if the Type ID is type_id, false otherwise.
Definition: type.cc:28
cerata::vhdl::Decl::Generate
static Block Generate(const Parameter &par, int depth=0)
Generate a parameter declaration as VHDL generic.
Definition: declaration.cc:72
cerata::vhdl::FilterForVHDL
std::vector< FlatType > FilterForVHDL(const std::vector< FlatType > &list)
Filter abstract types from a list of flattened types.
Definition: vhdl_types.cc:53
cerata::Named::name
std::string name() const
Return the name of the object.
Definition: utils.h:45
cerata::Type::STRING
@ STRING
No | No | No.
Definition: type.h:74
cerata::Term::Reverse
static Dir Reverse(Dir dir)
Return the inverse of a direction.
Definition: port.cc:64
cerata::intl
std::shared_ptr< Literal > intl(int64_t i)
Obtain a shared pointer to an integer literal from the default node pool.
Definition: pool.h:144
cerata::ToUpper
std::string ToUpper(std::string str)
Convert string to upper-case.
Definition: utils.cc:25
cerata::vhdl::ToString
std::string ToString(const std::vector< Block > &blocks)
Return a vector of blocks as a single string.
Definition: block.cc:186
cerata::Parameter
A Parameter node.
Definition: parameter.h:29
cerata::record
std::shared_ptr< Record > record(const std::string &name, const std::vector< std::shared_ptr< Field >> &fields)
Create a new Record type, and return a shared pointer to it.
Definition: type.cc:308
cerata::vhdl::Block
A block of code.
Definition: block.h:50
cerata::Flatten
void Flatten(std::vector< FlatType > *list, Type *type, const std::optional< FlatType > &parent, const std::string &name, bool invert, bool sep)
Flatten any Type.
Definition: flattype.cc:72
cerata::Type::INTEGER
@ INTEGER
No | No | No.
Definition: type.h:73
cerata::Node::ToString
virtual std::string ToString() const
Return a human-readable string of this node.
Definition: node.cc:35
cerata::PortArray
An array of port nodes.
Definition: array.h:123
cerata::Type::VECTOR
@ VECTOR
Yes | Yes | No.
Definition: type.h:71
cerata::NodeArray::size
Node * size() const
Return the size node.
Definition: array.h:43
cerata::port_array
std::shared_ptr< PortArray > port_array(const std::string &name, const std::shared_ptr< Type > &type, const std::shared_ptr< Node > &size, Port::Dir dir, const std::shared_ptr< ClockDomain > &domain)
Get a smart pointer to a new ArrayPort.
Definition: array.cc:175
cerata::Port
A port is a terminator node on a graph.
Definition: port.h:57
cerata::port
std::shared_ptr< Port > port(const std::string &name, const std::shared_ptr< Type > &type, Term::Dir dir, const std::shared_ptr< ClockDomain > &domain)
Make a new port with some name, type and direction.
Definition: port.cc:22
cerata::Node::type
Type * type() const
Return the node Type.
Definition: node.h:57
cerata::vhdl
Contains everything related to the VHDL back-end.
Definition: architecture.cc:31