Fletchgen
The Fletcher Design Generator
mantle.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/mantle.h"
16 
17 #include <cerata/api.h>
18 #include <fletcher/common.h>
19 
20 #include <memory>
21 #include <vector>
22 #include <utility>
23 #include <string>
24 #include <vector>
25 
26 #include "fletchgen/basic_types.h"
27 #include "fletchgen/bus.h"
28 #include "fletchgen/nucleus.h"
29 #include "fletchgen/axi4_lite.h"
30 #include "fletchgen/external.h"
31 
32 namespace fletchgen {
33 
34 using cerata::intl;
35 
36 //static std::string ArbiterMasterName(BusFunction function) {
37 // return std::string(function == BusFunction::READ ? "rd" : "wr") + "_mst";
38 //}
39 
40 Mantle::Mantle(std::string name,
41  const std::vector<std::shared_ptr<RecordBatch>> &recordbatches,
42  const std::shared_ptr<Nucleus> &nucleus,
43  BusDim bus_dim,
44  Axi4LiteSpec axi_spec)
45  : Component(std::move(name)), bus_dim_(bus_dim) {
46 
47  using std::pair;
48 
49  // Add some default parameters.
50  auto iw = index_width();
51  auto tw = tag_width();
52  Add({iw, tw});
53 
54  // Top level bus parameters.
55  auto bus_params = BusDimParams(this, bus_dim);
56  auto bus_rd_spec = BusSpecParams{bus_params, BusFunction::READ};
57  auto bus_wr_spec = BusSpecParams{bus_params, BusFunction::WRITE};
58  std::shared_ptr<Port> bus_rd = bus_port("rd_mst", Port::OUT, bus_rd_spec);
59  std::shared_ptr<Port> bus_wr = bus_port("wr_mst", Port::OUT, bus_wr_spec);
60 
61  // Add default ports; bus clock/reset, kernel clock/reset and AXI4-lite port.
62  auto bcr = port("bcd", cr(), Port::Dir::IN, bus_cd());
63  auto kcr = port("kcd", cr(), Port::Dir::IN, kernel_cd());
64  auto axi = axi4_lite(Port::Dir::IN, bus_cd(), axi_spec);
65  Add({bcr, kcr, axi});
66 
67  // Handle the Nucleus.
68  // Instantiate the nucleus and connect some default parameters.
69  nucleus_inst_ = Instantiate(nucleus.get());
70  nucleus_inst_->prt("kcd") <<= kcr;
71  nucleus_inst_->prt("mmio") <<= axi;
72 
73  nucleus_inst_->par("INDEX_WIDTH")->SetValue(iw);
74  nucleus_inst_->par("TAG_WIDTH")->SetValue(tw);
75 
76  // Handle RecordBatches.
77  // We've instantiated the Nucleus, and now we should feed it with data from the RecordBatch components.
78  // We're going to do the following while iterating over the RecordBatch components.
79  // 1. Instantiate every RecordBatch component.
80  // 2. Remember the memory interface ports (bus_ports) for bus infrastructure generation later on.
81  // 3. Connect all field-derived ports between RecordBatches and Nucleus.
82 
83  std::vector<BusPort *> rb_bus_ports;
84 
85  for (const auto &rb : recordbatches) {
86  // Instantiate the RecordBatch
87  auto rbi = Instantiate(rb.get());
88  recordbatch_instances_.push_back(rbi);
89 
90  // Connect bus clock/reset and kernel clock/reset.
91  rbi->prt("bcd") <<= bcr;
92  rbi->prt("kcd") <<= kcr;
93 
94  rbi->par("INDEX_WIDTH")->SetValue(iw);
95  rbi->par("TAG_WIDTH")->SetValue(tw);
96 
97  // Look up its bus ports and remember them.
98  auto rbi_bus_ports = rbi->GetAll<BusPort>();
99  rb_bus_ports.insert(rb_bus_ports.end(), rbi_bus_ports.begin(), rbi_bus_ports.end());
100 
101  // Obtain all the field-derived ports from the RecordBatch Instance.
102  auto field_ports = rbi->GetAll<FieldPort>();
103  // Depending on their function (and direction), connect all of them to the nucleus.
104  for (const auto &fp : field_ports) {
105  if (fp->function_ == FieldPort::Function::ARROW) {
106  // Connect the address width parameter on the nucleus.
107  auto prefix = rb->schema()->name() + "_" + fp->field_->name();
108  Connect(nucleus_inst_->par(bus_addr_width(0, prefix)), par(bus_addr_width()));
109 
110  // Connect the other bus params.
111  ConnectBusParam(rbi, prefix + "_", bus_params, inst_to_comp_map());
112 
113  if (fp->dir() == cerata::Term::Dir::OUT) {
114  Connect(nucleus_inst_->prt(fp->name()), fp);
115  } else {
116  Connect(fp, nucleus_inst_->prt(fp->name()));
117  }
118  } else if (fp->function_ == FieldPort::Function::COMMAND) {
119  Connect(fp, nucleus_inst_->prt(fp->name()));
120  } else if (fp->function_ == FieldPort::Function::UNLOCK) {
121  Connect(nucleus_inst_->prt(fp->name()), fp);
122  }
123  }
124  }
125 
126  // Handle the bus infrastructure.
127  // Now that we've instantiated and connected all RecordBatches on the Nucleus side, we need to connect their bus
128  // ports to bus arbiters. We don't have an elaborate interconnection generation step yet, so we just discern between
129  // read and write ports, assuming they will all get the same bus parametrization.
130  //
131  // Therefore, we only need a read and/or write arbiter, whatever mode RecordBatch is instantiated.
132  // We take the following steps.
133  // 1. instantiate them and connect them to the top level ports.
134  // 2. Connect every RecordBatch bus port to the corresponding arbiter.
135 
136  // Instantiate and connect arbiters to top level.
137  // Instance *arb_read = nullptr;
138  // Instance *arb_write = nullptr;
139 
140  // Gather all unique bus specs from RecordBatch bus interfaces.
141  std::vector<BusSpec> bus_specs;
142  for (const auto &bp : rb_bus_ports) {
143  bus_specs.push_back(BusSpec(bp->spec_));
144  }
145  cerata::FilterDuplicates(&bus_specs);
146 
147  // For every required bus, instantiate a bus arbiter.
148  std::unordered_map<BusSpec, Instance *> arb_map;
149  for (const auto &b : bus_specs) {
150  auto prefix = b.ToName();
151  Instance *inst = Instantiate(bus_arbiter(b.func), prefix + "_inst");
152 
153  // Connect clock and reset
154  inst->prt("bcd") <<= bcr;
155 
156  // TODO(johanpel): for now, we only support one top-level bus spec, so we connect all arbiter generics to it.
157  // Also we just connect the top-level port directly.
158  ConnectBusParam(inst, "", bus_params, this->inst_to_comp_map());
159  if (b.func == BusFunction::READ) {
160  Connect(bus_rd, inst->Get<Port>("mst"));
161  Add(bus_rd);
162  } else {
163  Connect(bus_wr, inst->Get<Port>("mst"));
164  Add(bus_wr);
165  }
166  arb_map[b] = inst;
167  }
168 
169  // Now we loop over all bus ports again and connect them to the arbiters.
170  for (const auto &bp : rb_bus_ports) {
171  // Select the corresponding arbiter.
172  auto arb = arb_map[BusSpec(bp->spec_)];
173  // Get the PortArray.
174  auto array = arb->prt_arr("bsv");
175  // Append the PortArray and connect.
176  Connect(array->Append(), bp);
177  }
178 
179  // Add and connect platform IO
180  auto ext = external();
181  if (ext) {
182  auto pf = cerata::port("ext", ext.value(), Port::Dir::OUT);
183  Add(pf);
184  Connect(pf, nucleus_inst_->prt("ext"));
185  }
186 }
187 
189 std::shared_ptr<Mantle> mantle(const std::string &name,
190  const std::vector<std::shared_ptr<RecordBatch>> &recordbatches,
191  const std::shared_ptr<Nucleus> &nucleus,
192  BusDim bus_spec,
193  Axi4LiteSpec axi_spec) {
194  return std::make_shared<Mantle>(name, recordbatches, nucleus, bus_spec, axi_spec);
195 }
196 
197 } // namespace fletchgen
std::vector< Instance * > recordbatch_instances_
The RecordBatch instances.
Definition: mantle.h:59
Mantle(std::string name, const std::vector< std::shared_ptr< RecordBatch >> &recordbatches, const std::shared_ptr< Nucleus > &nucleus, BusDim bus_dim, Axi4LiteSpec axi_spec)
Construct a Mantle based on a SchemaSet.
Definition: mantle.cc:40
std::shared_ptr< Nucleus > nucleus() const
Return the kernel component of this Mantle.
Definition: mantle.h:45
Instance * nucleus_inst_
Shortcut to the instantiated Nucleus.
Definition: mantle.h:57
Contains all classes and functions related to Fletchgen.
Definition: array.cc:29
std::shared_ptr< Mantle > mantle(const std::string &name, const std::vector< std::shared_ptr< RecordBatch >> &recordbatches, const std::shared_ptr< Nucleus > &nucleus, BusDim bus_spec, Axi4LiteSpec axi_spec)
Construct a Mantle and return a shared pointer to it.
Definition: mantle.cc:189
std::shared_ptr< Nucleus > nucleus(const std::string &name, const std::vector< std::shared_ptr< RecordBatch >> &recordbatches, const std::shared_ptr< Kernel > &kernel, const std::shared_ptr< Component > &mmio, Axi4LiteSpec axi_spec)
Make an Nucleus component based on RecordBatch components. Returns a shared pointer to the new Nucleu...
Definition: nucleus.cc:222
std::shared_ptr< ClockDomain > kernel_cd()
Fletcher accelerator clock domain.
Definition: basic_types.cc:62
std::shared_ptr< Type > cr()
Fletcher clock/reset;.
Definition: basic_types.cc:73
Component * bus_arbiter(BusFunction function)
Return a Cerata model of a BusArbiter.
Definition: bus.cc:82
std::shared_ptr< Axi4LitePort > axi4_lite(Port::Dir dir, const std::shared_ptr< ClockDomain > &domain, Axi4LiteSpec spec)
Make a new AXI4-lite port, returning a shared pointer to it.
Definition: axi4_lite.cc:67
void ConnectBusParam(cerata::Graph *dst, const std::string &prefix, const BusDimParams &src, cerata::NodeMap *rebinding)
Find and connect all prefixed bus params on a graph to the supplied source params,...
Definition: bus.cc:191
Component * array(Mode mode)
Return a Cerata component model of an Array(Reader/Writer).
Definition: array.cc:139
std::shared_ptr< ClockDomain > bus_cd()
Fletcher bus clock domain.
Definition: basic_types.cc:67
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.
AXI4-lite bus specification.
Definition: axi4_lite.h:29
Holds bus interface dimensions.
Definition: bus.h:48
Holds bus parameters based on bus dimensions, that has actual nodes representing the dimensions.
Definition: bus.h:68
A port derived from bus parameters.
Definition: bus.h:130
Holds bus dimensions and function, without instantiating Cerata nodes.
Definition: bus.h:100
Holds bus parameters and function based on bus dimensions, that has actual nodes representing the dim...
Definition: bus.h:90
A port derived from an Arrow field.
Definition: recordbatch.h:52
std::shared_ptr< arrow::Field > field_
The Arrow field this port was derived from.
Definition: recordbatch.h:63