Fletchgen
The Fletcher Design Generator
array.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 "fletchgen/array.h"
16 
17 #include <cerata/api.h>
18 #include <cerata/vhdl/vhdl.h>
19 #include <fletcher/common.h>
20 #include <utility>
21 #include <memory>
22 #include <cmath>
23 #include <vector>
24 #include <string>
25 
26 #include "fletchgen/bus.h"
27 #include "fletchgen/basic_types.h"
28 
29 namespace fletchgen {
30 
31 using cerata::vector;
32 using cerata::record;
33 using cerata::string;
34 using cerata::strl;
35 using cerata::boolean;
36 using cerata::booll;
37 using cerata::record;
38 using cerata::stream;
39 using cerata::integer;
40 using cerata::parameter;
41 
42 using fletcher::Mode;
43 
44 PARAM_FACTORY(index_width)
45 PARAM_FACTORY(tag_width)
46 
47 // The width of the indices or Arrow.
48 // TODO(johanpel): support LARGE_LIST, LARGE_BINARY, LARGE_STRING, etc...
49 static const int ARROW_OFFSET_WIDTH = 32;
50 
51 size_t GetCtrlBufferCount(const arrow::Field &field) {
52  fletcher::FieldMetadata field_meta;
53  fletcher::FieldAnalyzer fa(&field_meta);
54  fa.Analyze(field);
55  return field_meta.buffers.size();
56 }
57 
58 uint32_t GetTagWidth(const arrow::Field &field) {
59  return fletcher::GetUIntMeta(field, fletcher::meta::TAG_WIDTH, 1);
60 }
61 
62 std::shared_ptr<Type> cmd_type(const std::shared_ptr<Node> &index_width,
63  const std::shared_ptr<Node> &tag_width,
64  const std::optional<std::shared_ptr<Node>> &ctrl_width) {
65  // Create record
66  auto data = record({field("firstIdx", vector(index_width)),
67  field("lastIdx", vector(index_width)),
68  field("tag", vector(tag_width))});
69  // If we want the ctrl field to be visible on this type, create that as well. This field is used to pass addresses.
70  // Depending on how advanced the developer is, we want to expose this or leave it out through the Nucleus layer.
71  if (ctrl_width) {
72  auto ctrl = field(vector("ctrl", *ctrl_width));
73  data->AddField(ctrl, 2);
74  }
75  // Create the stream type.
76  auto result = stream(data);
77  return result;
78 }
79 
80 std::shared_ptr<Type> unlock_type(const std::shared_ptr<Node> &tag_width) {
81  std::shared_ptr<Type> unlock_stream = stream("tag", vector(tag_width));
82  return unlock_stream;
83 }
84 
85 std::shared_ptr<Type> array_reader_out(uint32_t num_streams, uint32_t full_width) {
86  auto data_stream = stream("ar_out", "", record({field(data(full_width)),
87  field(dvalid(num_streams, true)),
88  field(last(num_streams, true))}),
89  {field("valid", vector(num_streams)),
90  field("ready", vector(num_streams))->Reverse()});
91  return data_stream;
92 }
93 
94 std::shared_ptr<Type> array_writer_in(uint32_t num_streams, uint32_t full_width) {
95  auto data_stream = stream("aw_in", "", record({field(data(full_width)),
96  field(dvalid(num_streams, true)),
97  field(last(num_streams, true))}),
98  {field("valid", vector(num_streams)),
99  field("ready", vector(num_streams))->Reverse()});
100  return data_stream;
101 }
102 
103 std::shared_ptr<Type> array_reader_out(std::pair<uint32_t, uint32_t> spec) {
104  return array_reader_out(spec.first,
105  spec.second);
106 }
107 
108 std::shared_ptr<Type> array_writer_in(std::pair<uint32_t, uint32_t> spec) {
109  return array_writer_in(spec.first,
110  spec.second);
111 }
112 
113 static std::string ArrayName(fletcher::Mode mode) {
114  return mode == Mode::READ ? "ArrayReader" : "ArrayWriter";
115 }
116 
117 static std::string DataName(fletcher::Mode mode) {
118  return mode == Mode::READ ? "out" : "in";
119 }
120 
139 Component *array(Mode mode) {
140  // Check if the component already exists.
141  auto optional_existing = cerata::default_component_pool()->Get(ArrayName(mode));
142  if (optional_existing) {
143  return *optional_existing;
144  }
145  // Create anew component.
146  auto result = cerata::component(ArrayName(mode));
147 
148  BusDimParams params(result);
149  auto func = mode == Mode::READ ? BusFunction::READ : BusFunction::WRITE;
150  BusSpecParams spec{params, func};
151 
152  auto iw = index_width();
153  auto tw = tag_width();
154  tw->SetName("CMD_TAG_WIDTH");
155 
156  result->Add({iw,
157  parameter("CFG", std::string("")),
158  parameter("CMD_TAG_ENABLE", true),
159  tw});
160 
161  // Clocks and resets.
162  auto bcd = port("bcd", cr(), Port::Dir::IN, bus_cd());
163  auto kcd = port("kcd", cr(), Port::Dir::IN, kernel_cd());
164 
165  // Command port.
166  auto cmd = port("cmd", cmd_type(iw, tw, strl("arcfg_ctrlWidth(CFG, BUS_ADDR_WIDTH)")), Port::Dir::IN, kernel_cd());
167 
168  // Unlock port.
169  auto unlock = port("unl", unlock_type(tw), Port::Dir::OUT, kernel_cd());
170 
171  // Bus port.
172  auto bus = bus_port("bus", Port::Dir::OUT, spec);
173 
174  // Arrow data port.
175  auto type = mode == Mode::READ ? array_reader_out() : array_writer_in();
176  auto dir = mode == Mode::READ ? Port::Dir::OUT : Port::Dir::IN;
177  auto data = port(DataName(mode), type, dir, kernel_cd());
178 
179  // Insert ports
180  result->Add({bcd, kcd, cmd, unlock, bus, data});
181 
182  result->SetMeta(cerata::vhdl::meta::PRIMITIVE, "true");
183  result->SetMeta(cerata::vhdl::meta::LIBRARY, "work");
184  result->SetMeta(cerata::vhdl::meta::PACKAGE, "Array_pkg");
185  return result.get();
186 }
187 
188 ConfigType GetConfigType(const arrow::DataType &type) {
189  if (type.id() == arrow::Type::LIST) {
190  // Detect listprim:
191  // Elements must be non-nullable.
192  if (!type.field(0)->nullable() && (GetConfigType(*type.field(0)->type()) == ConfigType::PRIM)) {
193  return ConfigType::LIST_PRIM;
194  } else { // otherwise it's just a normal list
195  return ConfigType::LIST;
196  }
197  }
198  // listprim(8) types:
199  if (type.id() == arrow::Type::BINARY) return ConfigType::LIST_PRIM;
200  if (type.id() == arrow::Type::STRING) return ConfigType::LIST_PRIM;
201 
202  // Structs
203  if (type.id() == arrow::Type::STRUCT) return ConfigType::STRUCT;
204 
205  // Anything else should be a primitive.
206  return ConfigType::PRIM;
207 }
208 
209 std::shared_ptr<Node> GetWidthNode(const arrow::DataType &type) {
210  switch (type.id()) {
211  // Fixed-width:
212  case arrow::Type::BOOL: return intl(1);
213  case arrow::Type::DATE32: return intl(32);
214  case arrow::Type::DATE64: return intl(64);
215  case arrow::Type::DOUBLE: return intl(64);
216  case arrow::Type::FLOAT: return intl(32);
217  case arrow::Type::HALF_FLOAT: return intl(16);
218  case arrow::Type::INT8: return intl(8);
219  case arrow::Type::INT16: return intl(16);
220  case arrow::Type::INT32: return intl(32);
221  case arrow::Type::INT64: return intl(64);
222  case arrow::Type::TIME32: return intl(32);
223  case arrow::Type::TIME64: return intl(64);
224  case arrow::Type::TIMESTAMP: return intl(64);
225  case arrow::Type::UINT8: return intl(8);
226  case arrow::Type::UINT16: return intl(16);
227  case arrow::Type::UINT32: return intl(32);
228  case arrow::Type::UINT64: return intl(64);
229  case arrow::Type::DECIMAL: return intl(128);
230 
231  // Lists:
232  case arrow::Type::LIST: return strl("OFFSET_WIDTH");
233  case arrow::Type::BINARY: return strl("OFFSET_WIDTH");
234  case arrow::Type::STRING: return strl("OFFSET_WIDTH");
235 
236  // Others:
237  default:
238  // case arrow::Type::INTERVAL: return 0;
239  // case arrow::Type::MAP: return 0;
240  // case arrow::Type::NA: return 0;
241  // case arrow::Type::DICTIONARY: return 0;
242  // case arrow::Type::UNION: return 0;
243  throw std::domain_error("Arrow type " + type.ToString() + " not supported.");
244 
245  // Structs have no width
246  case arrow::Type::STRUCT: return intl(0);
247 
248  // Other width types:
249  case arrow::Type::FIXED_SIZE_BINARY: {
250  const auto *t = dynamic_cast<const arrow::FixedSizeBinaryType *>(&type);
251  return intl(t->bit_width());
252  }
253  }
254 }
255 
256 std::string GenerateConfigString(const arrow::Field &field, int level) {
257  std::string ret;
258  ConfigType ct = GetConfigType(*field.type());
259 
260  if (field.nullable()) {
261  ret += "null(";
262  level++;
263  }
264 
265  int epc = fletcher::GetUIntMeta(field, fletcher::meta::VALUE_EPC, 1);
266  int lepc = fletcher::GetUIntMeta(field, fletcher::meta::LIST_EPC, 1);
267 
268  bool has_children = false;
269 
270  if (ct == ConfigType::PRIM) {
271  auto w = GetWidthNode(*field.type());
272  ret += "prim(" + w->ToString();
273  level++;
274  } else if (ct == ConfigType::LIST_PRIM) {
275  ret += "listprim(";
276  level++;
277  // Binary and string have no child, so we can't inspect it for the width, which is always 8.
278  if ((field.type()->id() == arrow::Type::BINARY) || (field.type()->id() == arrow::Type::STRING)) {
279  ret += "8";
280  } else {
281  // Other list of non-nullable primitives:
282  ret += std::to_string(GetFixedWidthTypeBitWidth(*field.type()->field(0)->type()));
283  }
284  } else if (ct == ConfigType::LIST) {
285  has_children = true;
286  ret += "list(";
287  level++;
288  } else if (ct == ConfigType::STRUCT) {
289  has_children = true;
290  ret += "struct(";
291  level++;
292  }
293 
294  if (epc > 1 || lepc > 1) {
295  ret += ";";
296  }
297  if (epc > 1) {
298  ret += "epc=" + std::to_string(epc);
299  if (lepc > 1) {
300  ret += ",";
301  }
302  }
303  if (lepc > 1) {
304  ret += "lepc=" + std::to_string(epc);
305  }
306 
307  if (has_children) {
308  // Append children
309  for (int c = 0; c < field.type()->num_fields(); c++) {
310  auto child = field.type()->field(c);
311  ret += GenerateConfigString(*child);
312  if (c != field.type()->num_fields() - 1)
313  ret += ",";
314  }
315  }
316 
317  for (; level > 0; level--)
318  ret += ")";
319 
320  return ret;
321 }
322 
323 std::shared_ptr<TypeMapper> GetStreamTypeMapper(Type *stream_type, Type *other) {
324  auto result = TypeMapper::Make(stream_type, other);
325 
326  constexpr size_t idx_valid = 1;
327  constexpr size_t idx_ready = 2;
328  constexpr size_t idx_data = 4;
329  constexpr size_t idx_dvalid = 5;
330  constexpr size_t idx_last = 6;
331 
332  auto flat_stream = result->flat_a();
333  for (size_t i = 0; i < flat_stream.size(); i++) {
334  auto t = flat_stream[i].type_;
335  if (t->Is(Type::RECORD)) {
336  } else if (t == cerata::Stream::valid().get()) {
337  result->Add(i, idx_valid);
338  } else if (t == cerata::Stream::ready().get()) {
339  result->Add(i, idx_ready);
340  } else if (t->name() == dvalid()->name()) {
341  result->Add(i, idx_dvalid);
342  } else if (t->name() == last()->name()) {
343  result->Add(i, idx_last);
344  } else {
345  // If it's not any of the default control signals on the stream, it must be data.
346  result->Add(i, idx_data);
347  }
348  }
349  return result;
350 }
351 
352 std::shared_ptr<Type> ListPrimType(int val_epc, int list_epc, int val_width, int idx_width, const std::string &name) {
353  auto data_width = val_epc * val_width;
354  auto lengths_width = list_epc * idx_width;
355 
356  auto e_count_width = static_cast<int>(ceil(log2(val_epc + 1)));
357  auto l_count_width = static_cast<int>(ceil(log2(list_epc + 1)));
358 
359  return record({field("", stream(record({field("dvalid", dvalid()),
360  field("last", last()),
361  field("length", length(lengths_width)),
362  field("count", count(l_count_width))}))),
363  field(name, stream(record({field("dvalid", dvalid()),
364  field("last", last()),
365  field("", data(data_width)),
366  field("count", count(e_count_width))})))});
367 }
368 
369 std::shared_ptr<Type> GetStreamType(const arrow::Field &arrow_field, fletcher::Mode mode, int level) {
370  // The ordering of the record fields in this function determines the order in which a nested stream is type converted
371  // automatically using GetStreamTypeConverter. This corresponds to how the hardware is implemented.
372  // More specifically, this is how the data, count and validity fields are currently concatenated onto one big data
373  // field of the output and input streams of ArrayReaders/Writers.
374  //
375  // WARNING: Modifications to this function must be reflected in the manual hardware implementation of Fletcher
376  // components! See: hardware/arrays/ArrayConfig_pkg.vhd
377 
378  // Get the EPC values
379  int epc = fletcher::GetUIntMeta(arrow_field, fletcher::meta::VALUE_EPC, 1);
380  int lepc = fletcher::GetUIntMeta(arrow_field, fletcher::meta::LIST_EPC, 1);
381 
382  // Get their ceiled log2 to determine the count width
383  auto e_count_width = static_cast<int>(ceil(log2(epc + 1)));
384  auto l_count_width = static_cast<int>(ceil(log2(lepc + 1)));
385 
386  // Placeholder for the returning type.
387  std::shared_ptr<Type> type;
388 
389  // Determine what Cerata type to generate from the Arrow field type.
390  switch (arrow_field.type()->id()) {
391  // Special case: binary type has a length stream and non-nullable byte stream.
392  // The EPC is assumed to relate to the list values.
393  // The LEPC can be used for the length stream.
394  case arrow::Type::BINARY: return ListPrimType(epc, lepc, 8, ARROW_OFFSET_WIDTH, "bytes");
395  // Special case: string type has a length stream and non-nullable utf8 character stream.
396  // The EPC is assumed to relate to the list values.
397  // The LEPC can be used for the length stream.
398  // TODO(johanpel): reconsider the name of the chars stream.
399  case arrow::Type::STRING: return ListPrimType(epc, lepc, 8, ARROW_OFFSET_WIDTH, "chars");
400 
401  // Lists could be either lists of non-nullable primitives, or of something else.
402  // If the values are non-nullable primitives, we can use the "listprim" configuration, which has some additional
403  // options.
404  case arrow::Type::LIST: {
405  // Sanity check, a list should only have one child field.
406  if (arrow_field.type()->num_fields() != 1) {
407  FLETCHER_LOG(FATAL, "Encountered Arrow list type with other than 1 child.");
408  }
409  // Inspect the child field.
410  auto child_field = arrow_field.type()->field(0);
411  // First handle the special case where this can be made a listprim
412  if (GetConfigType(*child_field->type()) == ConfigType::PRIM) {
413  auto w = GetFixedWidthTypeBitWidth(*child_field->type());
414  FLETCHER_LOG(DEBUG, "Using \"listprim\" configuration for list of non-nullable primitives of width " << w);
415  auto values_type = ConvertFixedWidthType(arrow_field.type()->field(0)->type(), epc);
416  return ListPrimType(epc, lepc, w, ARROW_OFFSET_WIDTH, child_field->name());
417  } else {
418  // Lists of non-primitive types or nullable primitive types.
419  // EPC or LEPC are not supported.
420  if ((epc > 1) || (lepc > 1)) {
421  FLETCHER_LOG(FATAL, "(Length)-elements-per-cycle > 1 on non-primitive list is not supported.");
422  }
423  auto values_type = GetStreamType(*child_field, mode, level + 1);
424  auto child = stream(record({field("dvalid", dvalid()),
425  field("last", last()),
426  field("data", values_type),
427  field("count", count(e_count_width))}));
428  type = record({field("length", length(ARROW_OFFSET_WIDTH)),
429  field(child_field->name(), child)});
430  e_count_width = l_count_width;
431  }
432  break;
433  }
434 
435  // Structs
436  case arrow::Type::STRUCT: {
437  if (arrow_field.type()->num_fields() < 1) {
438  FLETCHER_LOG(FATAL, "Encountered Arrow struct type without any children.");
439  }
440  std::vector<std::shared_ptr<cerata::Field>> children;
441  for (const auto &f : arrow_field.type()->fields()) {
442  auto child_type = GetStreamType(*f, mode, level + 1);
443  children.push_back(field(f->name(), child_type));
444  }
445  type = record(arrow_field.name() + "_rec", children);
446  break;
447  }
448 
449  // Non-nested types
450  default: {
451  type = ConvertFixedWidthType(arrow_field.type(), epc);
452  break;
453  }
454  }
455 
456  // If this is a top level field, create a stream out of it
457  if (level == 0) {
458  // Create the stream record
459  auto rec = record({field("dvalid", dvalid()),
460  field("last", last())});
461  if (arrow_field.nullable()) {
462  rec->AddField(field("validity", validity()));
463  }
464 
465  rec->AddField(field("", type));
466 
467  if (epc > 1) {
468  rec->AddField(field("count", count(e_count_width)));
469  }
470  return stream(rec);
471  } else {
472  // Otherwise just return the type
473  return type;
474  }
475 }
476 
477 // TODO(johanpel): move this into GetStreamType
478 std::pair<uint32_t, uint32_t> GetArrayDataSpec(const arrow::Field &arrow_field) {
479 
480  uint32_t epc = fletcher::GetUIntMeta(arrow_field, fletcher::meta::VALUE_EPC, 1);
481  uint32_t lepc = fletcher::GetUIntMeta(arrow_field, fletcher::meta::LIST_EPC, 1);
482 
483  auto e_count_width = static_cast<int>(ceil(log2(epc + 1)));
484  auto l_count_width = static_cast<int>(ceil(log2(lepc + 1)));
485 
486  uint32_t validity_bit = arrow_field.nullable() ? 1 : 0;
487 
488  switch (arrow_field.type()->id()) {
489  case arrow::Type::BINARY: {
490  auto data_width = epc * 8;
491  auto length_width = lepc * 32;
492  return {2, e_count_width + l_count_width + data_width + length_width + validity_bit};
493  }
494 
495  case arrow::Type::STRING: {
496  auto data_width = epc * 8;
497  auto length_width = lepc * 32;
498  return {2, e_count_width + l_count_width + data_width + length_width + validity_bit};
499  }
500 
501  // Lists
502  case arrow::Type::LIST: {
503  auto child_field = arrow_field.type()->field(0);
504  if (GetConfigType(*child_field->type()) == ConfigType::PRIM) {
505  auto data_width = GetFixedWidthTypeBitWidth(*child_field->type());
506  return {2, e_count_width + l_count_width + data_width * epc + ARROW_OFFSET_WIDTH * lepc + validity_bit};
507  } else {
508  auto arrow_child = arrow_field.type()->field(0);
509  auto elem_spec = GetArrayDataSpec(*arrow_child);
510  // Add a length stream to number of streams, and length width to data width.
511  return {elem_spec.first + 1, elem_spec.second + ARROW_OFFSET_WIDTH + validity_bit};
512  }
513  }
514 
515  // Structs
516  case arrow::Type::STRUCT: {
517  if (epc > 1) {
518  FLETCHER_LOG(ERROR, "Multi-elements-per-cycle at struct-level is unsupported."
519  "Try to set EPC > 1 at struct field level.");
520  }
521  if (lepc > 1) {
522  FLETCHER_LOG(ERROR, "Struct delivers no length stream.");
523  }
524  if (arrow_field.type()->num_fields() < 1) {
525  FLETCHER_LOG(ERROR, "Encountered Arrow struct type without any children.");
526  }
527  auto spec = std::pair<int, int>{0, 0};
528  for (const auto &f : arrow_field.type()->fields()) {
529  auto child_spec = GetArrayDataSpec(*f);
530  spec.first += child_spec.first;
531  spec.second += child_spec.second;
532  }
533  return spec;
534  }
535 
536  // Non-nested types or unsupported types.
537  default: {
538  auto fwt = std::dynamic_pointer_cast<arrow::FixedWidthType>(arrow_field.type());
539  if (fwt == nullptr) {
540  FLETCHER_LOG(ERROR, "Unsupported Arrow type: " + arrow_field.type()->ToString());
541  }
542  return {1, (epc > 1 ? e_count_width : 0) + epc * (fwt->bit_width() + validity_bit)};
543  }
544  }
545 }
546 
547 } // namespace fletchgen
Contains all classes and functions related to Fletchgen.
Definition: array.cc:29
std::shared_ptr< Type > cmd_type(const std::shared_ptr< Node > &index_width, const std::shared_ptr< Node > &tag_width, const std::optional< std::shared_ptr< Node >> &ctrl_width)
Return a Fletcher command stream type.
Definition: array.cc:62
std::shared_ptr< ClockDomain > kernel_cd()
Fletcher accelerator clock domain.
Definition: basic_types.cc:62
std::shared_ptr< TypeMapper > GetStreamTypeMapper(Type *stream_type, Type *other)
Get a type mapper for an Arrow::Field-based stream to an ArrayReader/Writer stream.
Definition: array.cc:323
std::string GenerateConfigString(const arrow::Field &field, int level)
Return the configuration string for a ArrayReader/Writer.
Definition: array.cc:256
std::shared_ptr< Node > GetWidthNode(const arrow::DataType &type)
Return a node representing the width of a (flat) Arrow DataType.
Definition: array.cc:209
std::pair< uint32_t, uint32_t > GetArrayDataSpec(const arrow::Field &arrow_field)
Get the ArrayR/W number of streams and data width from an Arrow Field.
Definition: array.cc:478
std::shared_ptr< Type > cr()
Fletcher clock/reset;.
Definition: basic_types.cc:73
std::shared_ptr< Type > data(int width)
Fletcher data.
Definition: basic_types.cc:98
std::shared_ptr< Type > unlock_type(const std::shared_ptr< Node > &tag_width)
Fletcher unlock stream.
Definition: array.cc:80
std::shared_ptr< Type > bus(const BusSpecParams &spec)
Fletcher bus type with access mode conveyed through spec of params.
Definition: bus.cc:166
std::shared_ptr< Type > ConvertFixedWidthType(const std::shared_ptr< arrow::DataType > &arrow_type, int epc)
Convert a fixed-width arrow::DataType to a fixed-width Fletcher Type.
Definition: basic_types.cc:148
std::shared_ptr< Type > dvalid(int width, bool on_primitive)
Fletcher dvalid.
Definition: basic_types.cc:121
std::shared_ptr< Type > GetStreamType(const arrow::Field &arrow_field, fletcher::Mode mode, int level)
Convert an Arrow::Field into a stream type.
Definition: array.cc:369
std::shared_ptr< Type > length(int width)
Fletcher length.
Definition: basic_types.cc:106
std::shared_ptr< Type > count(int width)
Fletcher count.
Definition: basic_types.cc:113
uint32_t GetTagWidth(const arrow::Field &field)
Return the tag width of this field as a literal node. Settable through Arrow metadata....
Definition: array.cc:58
ConfigType
Types for ArrayReader/Writer configuration string.
Definition: array.h:62
@ LIST
Variable length fields.
@ PRIM
Primitive (fixed-width) fields.
@ LIST_PRIM
List of primitives. Can have EPC > 1.
@ STRUCT
Structs, composed of multiple fields.
std::shared_ptr< Type > array_writer_in(uint32_t num_streams, uint32_t full_width)
Fletcher write data.
Definition: array.cc:94
size_t GetCtrlBufferCount(const arrow::Field &field)
Return the number of buffers for the control field.
Definition: array.cc:51
Component * array(Mode mode)
Return a Cerata component model of an Array(Reader/Writer).
Definition: array.cc:139
int GetFixedWidthTypeBitWidth(const arrow::DataType &arrow_type)
Returns the bit-width of a fixed-width Arrow type. Throws if it's not a fixed-width type.
Definition: basic_types.cc:140
std::shared_ptr< ClockDomain > bus_cd()
Fletcher bus clock domain.
Definition: basic_types.cc:67
std::shared_ptr< Type > last(int width, bool on_primitive)
Fletcher last.
Definition: basic_types.cc:129
std::shared_ptr< BusPort > bus_port(const std::string &name, Port::Dir dir, const BusSpecParams &params)
Make a new port and return a shared pointer to it.
Definition: bus.cc:175
@ READ
Interface reads from memory.
@ WRITE
Interface writes to memory.
ConfigType GetConfigType(const arrow::DataType &type)
Return the configuration string type version of an arrow::DataType.
Definition: array.cc:188
std::shared_ptr< Type > array_reader_out(uint32_t num_streams, uint32_t full_width)
Fletcher read data.
Definition: array.cc:85
Holds bus parameters based on bus dimensions, that has actual nodes representing the dimensions.
Definition: bus.h:68
Holds bus parameters and function based on bus dimensions, that has actual nodes representing the dim...
Definition: bus.h:90