Skip to content

Commit 6d5ecde

Browse files
committed
Add feature to allow external I/O signals
1 parent 7f40ae8 commit 6d5ecde

18 files changed

+272
-79
lines changed

codegen/cpp/fletchgen/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ add_compile_unit(
6565
src/fletchgen/nucleus.cc
6666
src/fletchgen/profiler.cc
6767
src/fletchgen/axi4_lite.cc
68+
src/fletchgen/external.cc
6869

6970
src/fletchgen/srec/recordbatch.cc
7071
src/fletchgen/srec/srec.cc

codegen/cpp/fletchgen/README.md

+50
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,56 @@ your kernel implementation.
9494
| fletcher_profile | true / false | false | If set to true, mark this field for profiling. The hardware streams resulting from this field will have a profiler attached to them. |
9595
| fletcher_tag_width | 1 / 2 / 3 / ... | 1 | Width of the `tag` field of commands and unlock streams of RecordBatchReaders/Writers. Can be used to identify commands. |
9696

97+
# Custom MMIO registers
98+
You can add custom MMIO registers to your kernel using `--reg`.
99+
More information [can be found here](../../../docs/mmio.md).
100+
101+
# Custom external I/O
102+
103+
Sometimes, your kernel requires other I/O signals than just Arrow data streams
104+
in and out, and MMIO registers. There may be some other type of data source or
105+
sink in your design, there may be some platform-specific things you want to use,
106+
or etcetera.
107+
108+
You can supply Fletchgen with a YAML file describing what signals you want to
109+
draw between the kernel and the top-level. An example is shown below, where we
110+
want to handshake completion from the platform top-level with a `req` and `ack`
111+
bit.
112+
113+
```yaml
114+
- record:
115+
name: platform
116+
fields:
117+
- record:
118+
name: complete
119+
fields:
120+
- field:
121+
name: req
122+
width: 1
123+
- field:
124+
name: ack
125+
width: 1
126+
reverse: true
127+
```
128+
129+
This will result in the following signals appearing at the top-level:
130+
```vhdl
131+
ext_platform_complete_req : out std_logic;
132+
ext_platform_complete_ack : in std_logic
133+
```
134+
135+
* The signals are assumed to be driven by the kernel. To drive them from the top
136+
level, use:
137+
```yaml
138+
reverse: true
139+
```
140+
141+
* Fields with a width of 1 can be forced to be `std_logic_vector` instead of
142+
`std_logic` by using:
143+
```yaml
144+
vector: true
145+
```
146+
97147
# Further reading
98148

99149
You can generate a simulation top level and provide a Flatbuffer file with a

codegen/cpp/fletchgen/src/fletchgen/design.cc

+26
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
#include <cerata/api.h>
1616
#include <cerata/vhdl/vhdl.h>
17+
#include <cerata/yaml/yaml.h>
1718

1819
#include <string>
1920
#include <vector>
@@ -27,6 +28,7 @@
2728
#include "fletchgen/mmio.h"
2829
#include "fletchgen/profiler.h"
2930
#include "fletchgen/bus.h"
31+
#include "fletchgen/external.h"
3032

3133
namespace fletchgen {
3234

@@ -160,6 +162,7 @@ Design::Design(const std::shared_ptr<Options> &opts) {
160162
// Analyze schemas and recordbatches to get schema_set and batch_desc
161163
AnalyzeSchemas();
162164
AnalyzeRecordBatches();
165+
AnalyzeExternalIO();
163166
// Sanity check our design for equal number of schemas and recordbatch descriptions.
164167
if (schema_set->schemas().size() != batch_desc.size()) {
165168
FLETCHER_LOG(FATAL, "Number of Schemas and RecordBatchDescriptions does not match.");
@@ -250,4 +253,27 @@ std::vector<cerata::OutputSpec> Design::GetOutputSpec() {
250253
return result;
251254
}
252255

256+
void Design::AnalyzeExternalIO() {
257+
if (!options->externals_yaml.empty()) {
258+
// Read YAML
259+
auto fs = std::ifstream(options->externals_yaml);
260+
std::stringstream yaml;
261+
yaml << fs.rdbuf();
262+
263+
// Convert to field
264+
std::shared_ptr<cerata::Field> field;
265+
auto converter = cerata::yaml::YamlConverter(yaml.str(), &field);
266+
auto status = converter.Convert();
267+
if (!status.ok()) {
268+
FLETCHER_LOG(FATAL, status.msg());
269+
}
270+
271+
// Extract and store type
272+
auto ext_type = field->type();
273+
ext_type->SetName("_external");
274+
cerata::default_type_pool()->Add(ext_type);
275+
external = ext_type;
276+
}
277+
}
278+
253279
} // namespace fletchgen

codegen/cpp/fletchgen/src/fletchgen/design.h

+5
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ struct Design {
4141
void AnalyzeSchemas();
4242
/// @brief Analyze the supplied RecordBatches.
4343
void AnalyzeRecordBatches();
44+
/// @brief Analyze custom IO.
45+
void AnalyzeExternalIO();
4446

4547
/// The program options.
4648
std::shared_ptr<Options> options;
@@ -61,6 +63,9 @@ struct Design {
6163

6264
Axi4LiteSpec mmio_spec;
6365

66+
/// External signals type
67+
std::optional<std::shared_ptr<Type>> external;
68+
6469
/// The RecordBatchDescriptions to use in SREC generation.
6570
std::vector<fletcher::RecordBatchDescription> batch_desc;
6671

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// Copyright 2018-2020 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 <map>
16+
#include <cerata/api.h>
17+
18+
#include "fletchgen/external.h"
19+
#include "fletchgen/status.h"
20+
21+
namespace fletchgen {
22+
23+
auto external() -> std::optional<std::shared_ptr<cerata::Type>> {
24+
auto opt = cerata::default_type_pool()->Get("_external");
25+
if (opt) {
26+
return opt.value()->shared_from_this();
27+
} else {
28+
return std::nullopt;
29+
}
30+
}
31+
32+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// Copyright 2018-2020 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/api.h>
16+
17+
#include "fletchgen/status.h"
18+
19+
namespace fletchgen {
20+
21+
auto external() -> std::optional<std::shared_ptr<cerata::Type>>;
22+
23+
}

codegen/cpp/fletchgen/src/fletchgen/fletchgen.cc

+5-1
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,11 @@ int fletchgen(int argc, char **argv) {
141141
std::string axi_file_path = options->output_dir + "/vhdl/AxiTop.gen.vhd";
142142
FLETCHER_LOG(INFO, "Saving AXI top-level design to: " + axi_file_path);
143143
axi_file = std::ofstream(axi_file_path);
144-
fletchgen::top::GenerateAXITop(*design.mantle_comp, *design.schema_set, {&axi_file}, design.mmio_spec);
144+
fletchgen::top::GenerateAXITop(*design.mantle_comp,
145+
*design.schema_set,
146+
design.mmio_spec,
147+
design.external,
148+
{&axi_file});
145149
axi_file.close();
146150
}
147151

codegen/cpp/fletchgen/src/fletchgen/kernel.cc

+7
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "fletchgen/basic_types.h"
2323
#include "fletchgen/mmio.h"
2424
#include "fletchgen/array.h"
25+
#include "fletchgen/external.h"
2526

2627
namespace fletchgen {
2728

@@ -46,6 +47,7 @@ Kernel::Kernel(std::string name,
4647

4748
auto iw = index_width();
4849
auto tw = tag_width();
50+
4951
Add({iw, tw});
5052

5153
// Add ports going to/from RecordBatches.
@@ -81,6 +83,11 @@ Kernel::Kernel(std::string name,
8183
}
8284
}
8385

86+
// Add custom I/O
87+
auto ext = external();
88+
if (ext) {
89+
Add(cerata::port("ext", ext.value(), Port::Dir::OUT));
90+
}
8491
}
8592

8693
std::shared_ptr<Kernel> kernel(const std::string &name,

codegen/cpp/fletchgen/src/fletchgen/mantle.cc

+9
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include "fletchgen/bus.h"
2828
#include "fletchgen/nucleus.h"
2929
#include "fletchgen/axi4_lite.h"
30+
#include "fletchgen/external.h"
3031

3132
namespace fletchgen {
3233

@@ -174,6 +175,14 @@ Mantle::Mantle(std::string name,
174175
// Append the PortArray and connect.
175176
Connect(array->Append(), bp);
176177
}
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+
}
177186
}
178187

179188
/// @brief Construct a Mantle and return a shared pointer to it.

codegen/cpp/fletchgen/src/fletchgen/nucleus.cc

+9
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include "fletchgen/mmio.h"
2626
#include "fletchgen/profiler.h"
2727
#include "fletchgen/axi4_lite.h"
28+
#include "fletchgen/external.h"
2829

2930
namespace fletchgen {
3031

@@ -208,6 +209,14 @@ Nucleus::Nucleus(const std::string &name,
208209

209210
// Gather all Field-derived ports that require profiling on this Nucleus.
210211
ProfileDataStreams(mmio_inst);
212+
213+
// Add and connect platform IO
214+
auto ext = external();
215+
if (ext) {
216+
auto pf = cerata::port("ext", ext.value(), Port::Dir::OUT);
217+
Add(pf);
218+
Connect(pf, kernel_inst->prt("ext"));
219+
}
211220
}
212221

213222
std::shared_ptr<Nucleus> nucleus(const std::string &name,

codegen/cpp/fletchgen/src/fletchgen/options.cc

+3
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,9 @@ bool Options::Parse(Options *options, int argc, char **argv) {
6868
"step of the simulation. Init must be a hexadecimal value in the form of 0x01234ABCD.\n"
6969
"Example: \"-reg32 c:32:myh2kreg:0xDEADBEEF s:64:mk2hreg\"");
7070

71+
app.add_option("-e,--external", options->externals_yaml, "Path to YAML file describing external signals to drag "
72+
"between kernel and top-level.");
73+
7174
app.add_option("--bus_specs", options->bus_dims,
7275
"Specify top-level bus parameters.\n"
7376
"Value must be a tuple of the following form: \"aw,dw,lw,bs,bm\"\n"

codegen/cpp/fletchgen/src/fletchgen/options.h

+2
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ struct Options {
4444
std::string kernel_name = "Kernel";
4545
/// Custom 32-bit registers.
4646
std::vector<std::string> regs;
47+
/// File to parse for external signals to/from top level to kernel.
48+
std::string externals_yaml;
4749
/// Bus dimensions strings.
4850
std::vector<std::string> bus_dims = {"64,512,8,1,16"};
4951
/// Use 64-bits data width for AXI4-lite MMIO bus when true.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// Copyright 2018-2020 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+
#pragma once
16+
17+
#include <iostream>
18+
19+
#include <putong/status.h>
20+
21+
namespace fletchgen {
22+
23+
/// Return on error status.
24+
#define FLETCHGEN_ROE(s) { \
25+
auto status = s; \
26+
if (!status.ok()) return status; \
27+
} \
28+
void()
29+
30+
/// Error types.
31+
enum class Error {
32+
GenericError,
33+
YAMLError
34+
};
35+
36+
using Status = putong::Status<Error>;
37+
38+
}

codegen/cpp/fletchgen/src/fletchgen/top/axi.cc

+25-2
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@
1818
#include <cerata/vhdl/vhdl.h>
1919
#include <memory>
2020

21+
#include <cerata/api.h>
22+
#include <cerata/vhdl/vhdl.h>
23+
2124
#include "fletchgen/top/axi_template.h"
2225
#include "fletchgen/mantle.h"
2326

@@ -27,8 +30,9 @@ using cerata::vhdl::Template;
2730

2831
std::string GenerateAXITop(const Mantle &mantle,
2932
const SchemaSet &schema_set,
30-
const std::vector<std::ostream *> &outputs,
31-
Axi4LiteSpec axi_spec) {
33+
Axi4LiteSpec axi_spec,
34+
std::optional<std::shared_ptr<Type>> external,
35+
const std::vector<std::ostream *> &outputs) {
3236
// Template for AXI top level
3337
auto t = Template::FromString(axi_source);
3438

@@ -186,6 +190,25 @@ std::string GenerateAXITop(const Mantle &mantle,
186190
t.Replace("AXI_WRITE_CONVERTER", "");
187191
}
188192

193+
t.Replace("MANTLE_DECL", cerata::vhdl::Decl::Generate(mantle, false, 1).ToString());
194+
195+
if (external) {
196+
auto p_mantle = cerata::port("ext", external.value(), cerata::Port::Dir::OUT);
197+
auto p_top = cerata::port("ext", external.value(), cerata::Port::Dir::OUT);
198+
cerata::Connect(p_top, p_mantle);
199+
200+
auto decl_block = cerata::vhdl::Decl::Generate(*p_mantle, 2);
201+
decl_block <<= ";";
202+
auto inst_block = cerata::vhdl::Inst::GeneratePortMaps(*p_mantle);
203+
inst_block.indent = 3;
204+
inst_block << ",";
205+
206+
t.Replace("EXTERNAL_PORT_DECL", decl_block.ToString());
207+
t.Replace("EXTERNAL_INST_MAP", inst_block.ToString());
208+
} else {
209+
t.Replace("EXTERNAL_PORT_DECL", "");
210+
}
211+
189212
for (auto &o : outputs) {
190213
o->flush();
191214
*o << t.ToString();

0 commit comments

Comments
 (0)