Fletchgen
The Fletcher Design Generator
axi.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/top/axi.h"
16 
17 #include <cerata/api.h>
18 #include <cerata/vhdl/vhdl.h>
19 #include <memory>
20 
21 #include <cerata/api.h>
22 #include <cerata/vhdl/vhdl.h>
23 
24 #include "fletchgen/top/axi_template.h"
25 #include "fletchgen/mantle.h"
26 
27 namespace fletchgen::top {
28 
29 using cerata::vhdl::Template;
30 
31 std::string GenerateAXITop(const Mantle &mantle,
32  const SchemaSet &schema_set,
33  Axi4LiteSpec axi_spec,
34  std::optional<std::shared_ptr<Type>> external,
35  const std::vector<std::ostream *> &outputs) {
36  // Template for AXI top level
37  auto t = Template::FromString(axi_source);
38 
39  // Bus properties
40  t.Replace("BUS_ADDR_WIDTH", 64);
41  t.Replace("BUS_DATA_WIDTH", 512);
42  t.Replace("BUS_LEN_WIDTH", 8);
43  t.Replace("BUS_BURST_STEP_LEN", 1);
44  t.Replace("BUS_BURST_MAX_LEN", 64);
45 
46  // MMIO properties
47  t.Replace("MMIO_ADDR_WIDTH", axi_spec.addr_width);
48  t.Replace("MMIO_DATA_WIDTH", axi_spec.data_width);
49 
50  // Do not change this order, TODO: fix this in replacement code
51  t.Replace("FLETCHER_WRAPPER_NAME", mantle.name());
52  t.Replace("FLETCHER_WRAPPER_INST_NAME", mantle.name() + "_inst");
53 
54  if (schema_set.RequiresReading()) {
55  t.Replace("MST_RREQ_DECLARE",
56  " rd_mst_rreq_valid : out std_logic;\n"
57  " rd_mst_rreq_ready : in std_logic;\n"
58  " rd_mst_rreq_addr : out std_logic_vector(BUS_ADDR_WIDTH-1 downto 0);\n"
59  " rd_mst_rreq_len : out std_logic_vector(BUS_LEN_WIDTH-1 downto 0);\n"
60  " rd_mst_rdat_valid : in std_logic;\n"
61  " rd_mst_rdat_ready : out std_logic;\n"
62  " rd_mst_rdat_data : in std_logic_vector(BUS_DATA_WIDTH-1 downto 0);\n"
63  " rd_mst_rdat_last : in std_logic;\n");
64 
65  t.Replace("MST_RREQ_INSTANTIATE",
66  " rd_mst_rreq_valid => rd_mst_rreq_valid,\n"
67  " rd_mst_rreq_ready => rd_mst_rreq_ready,\n"
68  " rd_mst_rreq_addr => rd_mst_rreq_addr,\n"
69  " rd_mst_rreq_len => rd_mst_rreq_len,\n"
70  " rd_mst_rdat_valid => rd_mst_rdat_valid,\n"
71  " rd_mst_rdat_ready => rd_mst_rdat_ready,\n"
72  " rd_mst_rdat_data => rd_mst_rdat_data,\n"
73  " rd_mst_rdat_last => rd_mst_rdat_last,");
74 
75  t.Replace("AXI_READ_CONVERTER",
76  " -----------------------------------------------------------------------------\n"
77  " -- AXI read converter\n"
78  " -----------------------------------------------------------------------------\n"
79  " -- Buffering bursts is disabled (ENABLE_FIFO=false) because BufferReaders\n"
80  " -- are already able to absorb full bursts.\n"
81  " axi_read_conv_inst: AxiReadConverter\n"
82  " generic map (\n"
83  " ADDR_WIDTH => BUS_ADDR_WIDTH,\n"
84  " MASTER_DATA_WIDTH => BUS_DATA_WIDTH,\n"
85  " MASTER_LEN_WIDTH => BUS_LEN_WIDTH,\n"
86  " SLAVE_DATA_WIDTH => BUS_DATA_WIDTH,\n"
87  " SLAVE_LEN_WIDTH => BUS_LEN_WIDTH,\n"
88  " SLAVE_MAX_BURST => BUS_BURST_MAX_LEN,\n"
89  " ENABLE_FIFO => false,\n"
90  " SLV_REQ_SLICE_DEPTH => 0,\n"
91  " SLV_DAT_SLICE_DEPTH => 0,\n"
92  " MST_REQ_SLICE_DEPTH => 0,\n"
93  " MST_DAT_SLICE_DEPTH => 0\n"
94  " )\n"
95  " port map (\n"
96  " clk => bcd_clk,\n"
97  " reset_n => bcd_reset_n,\n"
98  " slv_bus_rreq_addr => rd_mst_rreq_addr,\n"
99  " slv_bus_rreq_len => rd_mst_rreq_len,\n"
100  " slv_bus_rreq_valid => rd_mst_rreq_valid,\n"
101  " slv_bus_rreq_ready => rd_mst_rreq_ready,\n"
102  " slv_bus_rdat_data => rd_mst_rdat_data,\n"
103  " slv_bus_rdat_last => rd_mst_rdat_last,\n"
104  " slv_bus_rdat_valid => rd_mst_rdat_valid,\n"
105  " slv_bus_rdat_ready => rd_mst_rdat_ready,\n"
106  " m_axi_araddr => m_axi_araddr,\n"
107  " m_axi_arlen => m_axi_arlen,\n"
108  " m_axi_arvalid => m_axi_arvalid,\n"
109  " m_axi_arready => m_axi_arready,\n"
110  " m_axi_arsize => m_axi_arsize,\n"
111  " m_axi_rdata => m_axi_rdata,\n"
112  " m_axi_rlast => m_axi_rlast,\n"
113  " m_axi_rvalid => m_axi_rvalid,\n"
114  " m_axi_rready => m_axi_rready\n"
115  " );");
116  } else {
117  t.Replace("MST_RREQ_DECLARE", "");
118  t.Replace("MST_RREQ_INSTANTIATE", "");
119  t.Replace("AXI_READ_CONVERTER", "");
120  }
121 
122  if (schema_set.RequiresWriting()) {
123  t.Replace("MST_WREQ_DECLARE",
124  " wr_mst_wreq_valid : out std_logic;\n"
125  " wr_mst_wreq_ready : in std_logic;\n"
126  " wr_mst_wreq_addr : out std_logic_vector(BUS_ADDR_WIDTH-1 downto 0);\n"
127  " wr_mst_wreq_len : out std_logic_vector(BUS_LEN_WIDTH-1 downto 0);\n"
128  " wr_mst_wreq_last : out std_logic;\n"
129  " wr_mst_wdat_valid : out std_logic;\n"
130  " wr_mst_wdat_ready : in std_logic;\n"
131  " wr_mst_wdat_data : out std_logic_vector(BUS_DATA_WIDTH-1 downto 0);\n"
132  " wr_mst_wdat_strobe : out std_logic_vector(BUS_DATA_WIDTH/8-1 downto 0);\n"
133  " wr_mst_wdat_last : out std_logic;"
134  " wr_mst_wrep_valid : in std_logic;"
135  " wr_mst_wrep_ready : out std_logic;"
136  " wr_mst_wrep_ok : in std_logic;"
137  );
138 
139  t.Replace("MST_WREQ_INSTANTIATE",
140  " wr_mst_wreq_valid => wr_mst_wreq_valid,\n"
141  " wr_mst_wreq_ready => wr_mst_wreq_ready,\n"
142  " wr_mst_wreq_addr => wr_mst_wreq_addr,\n"
143  " wr_mst_wreq_len => wr_mst_wreq_len,\n"
144  " wr_mst_wreq_last => wr_mst_wreq_last,\n"
145  " wr_mst_wdat_valid => wr_mst_wdat_valid,\n"
146  " wr_mst_wdat_ready => wr_mst_wdat_ready,\n"
147  " wr_mst_wdat_data => wr_mst_wdat_data,\n"
148  " wr_mst_wdat_strobe => wr_mst_wdat_strobe,\n"
149  " wr_mst_wdat_last => wr_mst_wdat_last,\n"
150  " wr_mst_wrep_valid => wr_mst_wrep_valid,\n"
151  " wr_mst_wrep_ready => wr_mst_wrep_ready,\n"
152  " wr_mst_wrep_ok => wr_mst_wrep_ok,");
153 
154  t.Replace("AXI_WRITE_CONVERTER",
155  " -----------------------------------------------------------------------------\n"
156  " -- AXI write converter\n"
157  " -----------------------------------------------------------------------------\n"
158  " -- Buffering bursts is disabled (ENABLE_FIFO=false) because BufferWriters\n"
159  " -- are already able to absorb full bursts.\n"
160  " axi_write_conv_inst: AxiWriteConverter\n"
161  " generic map (\n"
162  " ADDR_WIDTH => BUS_ADDR_WIDTH,\n"
163  " MASTER_DATA_WIDTH => BUS_DATA_WIDTH,\n"
164  " MASTER_LEN_WIDTH => BUS_LEN_WIDTH,\n"
165  " SLAVE_DATA_WIDTH => BUS_DATA_WIDTH,\n"
166  " SLAVE_LEN_WIDTH => BUS_LEN_WIDTH,\n"
167  " SLAVE_MAX_BURST => BUS_BURST_MAX_LEN,\n"
168  " ENABLE_FIFO => false,\n"
169  " SLV_REQ_SLICE_DEPTH => 0,\n"
170  " SLV_DAT_SLICE_DEPTH => 0,\n"
171  " MST_REQ_SLICE_DEPTH => 0,\n"
172  " MST_DAT_SLICE_DEPTH => 0\n"
173  " )\n"
174  " port map (\n"
175  " clk => bcd_clk,\n"
176  " reset_n => bcd_reset_n,\n"
177  " slv_bus_wreq_addr => wr_mst_wreq_addr,\n"
178  " slv_bus_wreq_len => wr_mst_wreq_len,\n"
179  " slv_bus_wreq_valid => wr_mst_wreq_valid,\n"
180  " slv_bus_wreq_ready => wr_mst_wreq_ready,\n"
181  " slv_bus_wreq_last => wr_mst_wreq_last,\n"
182  " slv_bus_wdat_data => wr_mst_wdat_data,\n"
183  " slv_bus_wdat_strobe => wr_mst_wdat_strobe,\n"
184  " slv_bus_wdat_last => wr_mst_wdat_last,\n"
185  " slv_bus_wdat_valid => wr_mst_wdat_valid,\n"
186  " slv_bus_wdat_ready => wr_mst_wdat_ready,\n"
187  " slv_bus_wrep_valid => wr_mst_wrep_valid,\n"
188  " slv_bus_wrep_ready => wr_mst_wrep_ready,\n"
189  " slv_bus_wrep_ok => wr_mst_wrep_ok,\n"
190  " m_axi_awaddr => m_axi_awaddr,\n"
191  " m_axi_awlen => m_axi_awlen,\n"
192  " m_axi_awvalid => m_axi_awvalid,\n"
193  " m_axi_awready => m_axi_awready,\n"
194  " m_axi_awsize => m_axi_awsize,\n"
195  " m_axi_awuser => m_axi_awuser,\n"
196  " m_axi_wdata => m_axi_wdata,\n"
197  " m_axi_wstrb => m_axi_wstrb,\n"
198  " m_axi_wlast => m_axi_wlast,\n"
199  " m_axi_wvalid => m_axi_wvalid,\n"
200  " m_axi_wready => m_axi_wready,\n"
201  " m_axi_bvalid => m_axi_bvalid,\n"
202  " m_axi_bready => m_axi_bready,\n"
203  " m_axi_bresp => m_axi_bresp\n"
204  " );");
205  } else {
206  t.Replace("MST_WREQ_DECLARE", "");
207  t.Replace("MST_WREQ_INSTANTIATE", "");
208  t.Replace("AXI_WRITE_CONVERTER", "");
209  }
210 
211  t.Replace("MANTLE_DECL", cerata::vhdl::Decl::Generate(mantle, false, 1).ToString());
212 
213  if (external) {
214  auto p_mantle = cerata::port("ext", external.value(), cerata::Port::Dir::OUT);
215  auto p_top = cerata::port("ext", external.value(), cerata::Port::Dir::OUT);
216  cerata::Connect(p_top, p_mantle);
217 
218  auto decl_block = cerata::vhdl::Decl::Generate(*p_mantle, 2);
219  decl_block <<= ";";
220  auto inst_block = cerata::vhdl::Inst::GeneratePortMaps(*p_mantle);
221  inst_block.indent = 3;
222  inst_block << ",";
223 
224  t.Replace("EXTERNAL_PORT_DECL", decl_block.ToString());
225  t.Replace("EXTERNAL_INST_MAP", inst_block.ToString());
226  } else {
227  t.Replace("EXTERNAL_PORT_DECL", "");
228  t.Replace("EXTERNAL_INST_MAP", "");
229  }
230 
231  for (auto &o : outputs) {
232  o->flush();
233  *o << t.ToString();
234  }
235 
236  return t.ToString();
237 }
238 
239 } // namespace fletchgen::top
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