P4C
The P4 Compiler
Loading...
Searching...
No Matches
tofino/memories.h
1
18
19#ifndef BF_P4C_MAU_TOFINO_MEMORIES_H_
20#define BF_P4C_MAU_TOFINO_MEMORIES_H_
21
22#include <algorithm>
23
24#include "backends/tofino/bf-p4c/mau/action_format.h"
25#include "backends/tofino/bf-p4c/mau/attached_entries.h"
26#include "backends/tofino/bf-p4c/mau/instruction_memory.h"
27#include "backends/tofino/bf-p4c/mau/memories.h"
28#include "backends/tofino/bf-p4c/mau/table_format.h"
29#include "backends/tofino/bf-p4c/mau/tofino/input_xbar.h"
30#include "ir/ir.h"
31#include "lib/safe_vector.h"
32
33namespace Tofino {
34// Despite the namespace name, this code is shared for Tofino and JBay (Tofino 1/2)
35using namespace P4;
36
37struct Memories : public ::Memories {
38 /* track memory allocations within a single stage */
39 static constexpr int SRAM_ROWS = 8;
40 static constexpr int SRAM_COLUMNS = 10;
41 static constexpr int STASH_UNITS = 2;
42 static constexpr int LOGICAL_TABLES = 16;
43 static constexpr int LEFT_SIDE_COLUMNS = 4;
44 static constexpr int RIGHT_SIDE_COLUMNS = SRAM_COLUMNS - LEFT_SIDE_COLUMNS;
45 static constexpr int LEFT_SIDE_RAMS = LEFT_SIDE_COLUMNS * SRAM_ROWS;
46 static constexpr int RIGHT_SIDE_RAMS = RIGHT_SIDE_COLUMNS * SRAM_ROWS;
47 static constexpr int MAPRAM_COLUMNS = 6;
48 static constexpr int MAPRAM_MASK = (1U << MAPRAM_COLUMNS) - 1;
49 static constexpr int SRAM_DEPTH = 1024;
50 static constexpr int TCAM_ROWS = 12;
51 static constexpr int TCAM_COLUMNS = 2;
52 static constexpr int TCAM_DEPTH = 512;
53 static constexpr int TABLES_MAX = 16;
54 static constexpr int TERNARY_TABLES_MAX = 8;
55 static constexpr int ACTION_TABLES_MAX = 16;
56 static constexpr int GATEWAYS_PER_ROW = 2;
57 static constexpr int BUS_COUNT = 2; // search/result busses per row
58 static constexpr int PAYLOAD_COUNT = 2; // payload per row
59 static constexpr int STATS_ALUS = 4;
60 static constexpr int METER_ALUS = 4;
61 static constexpr int MAX_DATA_SWBOX_ROWS = 5;
62 static constexpr int COLOR_MAPRAM_PER_ROW = 4;
63 static constexpr int IMEM_ADDRESS_BITS = 6;
64 static constexpr int IMEM_LOOKUP_BITS = 3;
65 static constexpr int NUM_IDLETIME_BUS = 10;
66 static constexpr int MAX_PARTITION_RAMS_PER_ROW = 5;
67 static constexpr int MATCH_CENTRAL_ROW = 4;
68 static constexpr int MAX_STATS_ROW_PER_ALU = 3;
69 static constexpr int MAX_STATS_RAM_PER_ALU = MAPRAM_COLUMNS * MAX_STATS_ROW_PER_ALU;
70 static constexpr int MAX_METERS_ROW_PER_ALU = 4;
71 static constexpr int MAX_METERS_RAM_PER_ALU = MAPRAM_COLUMNS * MAX_METERS_ROW_PER_ALU;
72 static constexpr int MAX_METERS_COLOR_MAPRAM_PER_ALU = 5; // round up of 18 / 4
73
74 static constexpr int LOGICAL_ROW_MISSING_OFLOW = 8;
75
76 using Use = ::Memories::Use;
77
78 private:
108 struct search_bus_info {
109 cstring name;
110 // word number in exact match format
111 int width_section = 0; // Each search bus for a table has a particular width
112 int hash_group = 0; // Each hash function requires a different hash function
113 bool init = false;
114
115 search_bus_info() = default;
116 search_bus_info(cstring n, int ws, int hg)
117 : name(n), width_section(ws), hash_group(hg), init(true) {}
118
119 bool operator==(const search_bus_info &sbi) {
120 return name == sbi.name && width_section == sbi.width_section &&
121 hash_group == sbi.hash_group;
122 }
123
124 bool operator!=(const search_bus_info &sbi) { return !operator==(sbi); }
125
126 bool free() { return !init; }
127 };
128 friend std::ostream &operator<<(std::ostream &, const search_bus_info &);
129
130 struct result_bus_info {
131 cstring name;
132 int width_section = 0; // Each width section may require a different width section
133 int logical_table = 0; // For ATCAM tables, each logical table requires a separate
134 // result bus
135 bool init = false;
136
137 result_bus_info() {}
138 result_bus_info(cstring n, int ws, int lt)
139 : name(n), width_section(ws), logical_table(lt), init(true) {}
140
141 bool operator==(const result_bus_info &mbi) {
142 return name == mbi.name && width_section == mbi.width_section &&
143 logical_table == mbi.logical_table;
144 }
145
146 bool operator!=(const result_bus_info &mbi) { return !operator==(mbi); }
147 bool free() { return !init; }
148 };
149 friend std::ostream &operator<<(std::ostream &, const result_bus_info &);
150
152 unsigned sram_inuse[SRAM_ROWS] = {0};
156 // FIXME (Refactoring): Remove sram_print_result_bus / sram_print_search_bus
157 // and move the info inside and move into main result_bus_info /
158 // search_bus_info class
163 // int tcam_group_use[TCAM_ROWS][TCAM_COLUMNS] = {{-1}};
164 int tcam_midbyte_use[TCAM_ROWS / 2][TCAM_COLUMNS] = {{-1}};
170 BFN::Alloc1D<std::pair<cstring, int>, SRAM_ROWS - 1> vert_overflow_bus;
172 unsigned mapram_inuse[SRAM_ROWS] = {0};
174 bool gw_bytes_reserved[SRAM_ROWS][BUS_COUNT] = {{false}};
177
178 struct mem_info {
179 int logical_tables = 0;
180 int match_tables = 0;
181 int result_bus_min = 0;
182 int atcam_tables = 0;
183 int match_RAMs = 0;
184 int tind_tables = 0;
185 int tind_RAMs = 0;
186 int action_tables = 0;
187 int action_bus_min = 0;
188 int action_RAMs = 0;
189 int ternary_tables = 0;
190 int ternary_TCAMs = 0;
191 int stats_tables = 0;
192 int stats_RAMs = 0;
193 int meter_tables = 0;
194 int meter_RAMs = 0;
195 int stateful_tables = 0;
196 int stateful_RAMs = 0;
197 int selector_tables = 0;
198 int selector_RAMs = 0;
199 int no_match_tables = 0;
200 int independent_gw_tables = 0;
201 int idletime_RAMs = 0;
202
203 void clear() { memset(this, 0, sizeof(mem_info)); }
204
205 int total_RAMs() const {
206 return match_RAMs + action_RAMs + stats_RAMs + meter_RAMs + selector_RAMs + tind_RAMs;
207 }
208
209 int left_side_RAMs() const { return tind_RAMs; }
210 int right_side_RAMs() const {
211 return meter_RAMs + stats_RAMs + selector_RAMs + stateful_RAMs;
212 }
213 int non_SRAM_RAMs() const { return left_side_RAMs() + right_side_RAMs() + action_RAMs; }
214 int columns(int RAMs) const { return (RAMs + SRAM_COLUMNS - 1) / SRAM_COLUMNS; }
215 bool constraint_check(int lt_allowed, cstring &failure_reason) const;
216 };
217
218 friend class SetupAttachedTables;
219
220 // The resource information required for an individual IR::MAU::Table object in a single
221 // stage. Could coordinate to multiple logical tables, (i.e. dleft or atcam tables)
222 struct table_alloc {
223 const IR::MAU::Table *table;
224 const ::IXBar::Use *match_ixbar;
225 const TableFormat::Use *table_format;
226 const InstructionMemory::Use *instr_mem;
227 const ActionData::Format::Use *action_format;
228 std::map<UniqueId, Memories::Use> *memuse;
229 const LayoutOption *layout_option;
230 ActionData::FormatType_t format_type;
231 int provided_entries;
232 attached_entries_t attached_entries;
233 // Entries per match table allocation_unit (logical table) of the table. This is
234 // used to determine the attached table requirements if direct
235 safe_vector<int> calc_entries_per_uid;
236 int total_entries() const {
237 return std::accumulate(calc_entries_per_uid.begin(), calc_entries_per_uid.end(), 0);
238 }
239 int attached_gw_bytes = 0;
240 int stage_table = -1;
241 // Linked gw/match table that uses the same result bus
242 table_alloc *table_link = nullptr;
243 // FIXME -- hack to avoid problems in payload calculation when the only reason we
244 // have a payload is to set the match address
245 bool payload_match_addr_only = false;
246 table_alloc(const IR::MAU::Table *t, const ::IXBar::Use *mi, const TableFormat::Use *tf,
248 std::map<UniqueId, Memories::Use> *mu, const LayoutOption *lo,
249 ActionData::FormatType_t ft, const int e, const int st,
250 attached_entries_t attached_entries)
251 : table(t),
252 match_ixbar(mi),
253 table_format(tf),
254 instr_mem(im),
255 action_format(af),
256 memuse(mu),
257 layout_option(lo),
258 format_type(ft),
259 provided_entries(e),
260 attached_entries(attached_entries),
261 attached_gw_bytes(0),
262 stage_table(st),
263 table_link(nullptr) {}
264 void link_table(table_alloc *ta) { table_link = ta; }
265 int analysis_priority() const;
266
267 UniqueId build_unique_id(
268 const IR::MAU::AttachedMemory *at = nullptr, bool is_gw = false, int logical_table = -1,
269 UniqueAttachedId::pre_placed_type_t ppt = UniqueAttachedId::NO_PP) const;
270
271 safe_vector<UniqueId> allocation_units(
272 const IR::MAU::AttachedMemory *at = nullptr, bool is_gw = false,
273 UniqueAttachedId::pre_placed_type_t ppt = UniqueAttachedId::NO_PP) const;
274
275 safe_vector<UniqueId> unattached_units(
276 const IR::MAU::AttachedMemory *at = nullptr,
277 UniqueAttachedId::pre_placed_type_t ppt = UniqueAttachedId::NO_PP) const;
278
279 safe_vector<UniqueId> accounted_units(
280 const IR::MAU::AttachedMemory *at = nullptr,
281 UniqueAttachedId::pre_placed_type_t ppt = UniqueAttachedId::NO_PP) const;
282 };
283 int logical_tables_allowed = LOGICAL_TABLES;
284
285 friend std::ostream &operator<<(std::ostream &out, const Memories::table_alloc &ta);
286
288 struct SRAM_group : public IHasDbPrint {
289 table_alloc *ta; // Link to the table alloc to be generated
290 int depth = 0; // Individual number of RAMs required for a group
291 int width = 0; // How wide an individual group is, only needed for exact match
292 int placed = 0; // How many have been allocated so far
293 int number = 0; // Used to keep track of wide action tables and way numbers in exact match
294 int hash_group = -1; // Which hash group the exact match way is using
295 int logical_table = -1; // For ATCAM tables, which logical table this partition is based
296 int vpn_increment = 1;
297 int vpn_offset = 0;
298 int vpn_spare = 0;
299 bool direct = false; // Whether the attached table is directly or indirectly addressed
300 const IR::MAU::AttachedMemory *attached = nullptr;
301 UniqueAttachedId::pre_placed_type_t ppt = UniqueAttachedId::NO_PP;
302 int recent_home_row = -1; // For swbox users, most recent row to oflow to
303 enum type_t {
304 EXACT,
305 ACTION,
306 STATS,
307 METER,
308 REGISTER,
309 SELECTOR,
310 TIND,
311 IDLETIME,
312 ATCAM,
313 GROUP_TYPES
314 } type;
315
316 // Color Mapram Requirements, necessary for METER groups
318 int needed = 0;
319 int placed = 0;
320 // Necessary for stats addressed color maprams
321 int home_row = -1;
322 IR::MAU::ColorMapramAddress cma = IR::MAU::ColorMapramAddress::NOT_SET;
323 bool all_placed() const {
324 BUG_CHECK(placed <= needed, "Placed more color map RAMs than actually needed");
325 return needed == placed;
326 }
327 int left_to_place() const {
328 BUG_CHECK(placed <= needed, "Placed more color map RAMs than actually needed");
329 return needed - placed;
330 }
331
332 bool require_stats() const { return cma == IR::MAU::ColorMapramAddress::STATS; }
333 };
334
335 // Linkage between selectors and the corresponding action table in order to prevent
336 // a collision on the selector overflow
338 SRAM_group *sel_group = nullptr;
339 ordered_set<SRAM_group *> action_groups;
340 bool sel_linked() { return sel_group != nullptr; }
341 bool act_linked() { return !action_groups.empty(); }
342 bool sel_all_placed() const { return sel_group->all_placed(); }
343 bool action_all_placed() const {
344 if (action_groups.empty()) BUG("No action corresponding with this selector");
345 for (auto *action_group : action_groups) {
346 if (!action_group->all_placed()) return false;
347 }
348 return true;
349 }
350 bool sel_any_placed() const { return sel_group->any_placed(); }
351 bool action_any_placed() const {
352 if (action_groups.empty()) BUG("No action corresponding with this selector");
353 for (auto *action_group : action_groups) {
354 if (action_group->any_placed()) return true;
355 }
356 return false;
357 }
358
359 bool all_placed() const { return sel_all_placed() && action_all_placed(); }
360
361 bool is_act_corr_group(SRAM_group *corr) {
362 return action_groups.find(corr) != action_groups.end();
363 }
364 bool is_sel_corr_group(SRAM_group *corr) { return corr == sel_group; }
365 bool one_action_left() const {
366 int total_unplaced_groups = 0;
367 for (auto *action_group : action_groups)
368 if (action_group->left_to_place() > 0) total_unplaced_groups++;
369 return total_unplaced_groups == 1;
370 }
371 int action_left_to_place() const {
372 int left_to_place = 0;
373 for (auto *action_group : action_groups)
374 left_to_place += action_group->left_to_place();
375 return left_to_place;
376 }
377 SRAM_group *action_group_left() {
378 if (!one_action_left())
379 BUG("Trying to call action_group_left with more than one action left");
380 for (auto *action_group : action_groups)
381 if (action_group->left_to_place() > 0) return action_group;
382 return nullptr;
383 }
384 };
385 selector_info sel;
387 bool requires_ab = false; // LPF and WRED meters require synth and action bus
388
389 SRAM_group(table_alloc *t, int d, int w, int n, type_t ty)
390 : ta(t), depth(d), width(w), number(n), type(ty) {}
391 SRAM_group(table_alloc *t, int d, int n, type_t ty)
392 : ta(t), depth(d), number(n), type(ty) {}
393 SRAM_group(table_alloc *t, int d, int w, int n, int h, type_t ty)
394 : ta(t), depth(d), width(w), number(n), hash_group(h), type(ty) {}
395 void dbprint(std::ostream &out) const override;
396 search_bus_info build_search_bus(int width_sect) const {
397 return search_bus_info(ta->table->name, width_sect, hash_group);
398 }
399
400 result_bus_info build_result_bus(int width_sect) const;
401
402 int left_to_place() const {
403 BUG_CHECK(placed <= depth, "Placed more than needed");
404 return depth - placed;
405 }
406 bool all_placed() const {
407 BUG_CHECK(placed <= depth, "Placed more than needed");
408 return (depth == placed);
409 }
410 bool any_placed() { return (placed != 0); }
411 bool needs_ab() { return requires_ab && !all_placed(); }
412 bool is_synth_type() const {
413 return type == STATS || type == METER || type == REGISTER || type == SELECTOR;
414 }
415 bool sel_act_placed(SRAM_group *corr) {
416 return type == ACTION && sel.sel_linked() && sel.is_sel_corr_group(corr) &&
417 corr->sel.action_all_placed();
418 }
419 int RAMs_required() const {
420 if (type == SELECTOR) {
421 int action_depth = 0;
422 for (auto *action_group : sel.action_groups) action_depth += action_group->depth;
423 return depth + action_depth;
424 } else {
425 return depth;
426 }
427 }
428 int total_left_to_place() const {
429 if (type == SELECTOR) {
430 int action_depth = 0;
431 for (auto *action_group : sel.action_groups)
432 action_depth += action_group->left_to_place();
433 return left_to_place() + action_depth;
434 } else {
435 return left_to_place();
436 }
437 }
438
439 int maprams_left_to_place() const {
440 if (is_synth_type()) return left_to_place() + cm.left_to_place();
441 return 0;
442 }
443
444 // cstring get_name() const;
445 UniqueId build_unique_id() const;
446 bool same_wide_action(const SRAM_group &a);
447 int calculate_next_vpn() const { return placed * vpn_increment + vpn_offset; }
448 };
449
450 struct match_selection {
451 safe_vector<int> rows;
452 safe_vector<int> cols;
453 std::map<int, int> widths;
454 std::map<int, int> search_buses;
455 std::map<int, int> result_buses;
456 unsigned column_mask = 0;
457 };
458
459 enum switchbox_t { ACTION = 0, SYNTH, OFLOW, SWBOX_TYPES };
460
461 struct LogicalRowUser {
462 SRAM_group *group = nullptr;
463 switchbox_t bus = SWBOX_TYPES;
464 bitvec RAM_mask;
465 bitvec map_RAM_mask;
466
467 operator bool() const { return group != nullptr; }
468 void clear_masks() {
469 RAM_mask.clear();
470 map_RAM_mask.clear();
471 }
472 void clear() {
473 group = nullptr;
474 bus = SWBOX_TYPES;
475 clear_masks();
476 }
477 bool set() const { return !(RAM_mask.empty() && map_RAM_mask.empty()); }
478
479 bitvec color_map_RAM_mask() const {
480 BUG_CHECK(group->type == SRAM_group::METER,
481 "Cannot get color map RAMs of "
482 " a non-METER");
483 return map_RAM_mask - (RAM_mask >> LEFT_SIDE_COLUMNS);
484 }
485
486 void dbprint(std::ostream &out) const {
487 out << *group << " bus " << bus << " RAM mask: 0x" << RAM_mask << " map RAM mask: 0x"
488 << map_RAM_mask;
489 }
490 LogicalRowUser(SRAM_group *g, switchbox_t b) : group(g), bus(b) {}
491 };
492
494 struct swbox_fill {
495 SRAM_group *group = nullptr;
496 unsigned mask = 0;
497 unsigned mapram_mask = 0;
498 operator bool() const { return group != nullptr; }
499 swbox_fill() {}
500 void clear() {
501 group = nullptr;
502 mask = 0;
503 mapram_mask = 0;
504 }
505 void clear_masks() {
506 mask = 0;
507 mapram_mask = 0;
508 }
509 void dbprint(std::ostream &out) const {
510 out << *group << " RAM mask: 0x" << P4::hex(mask) << " map RAM mask: 0x"
511 << P4::hex(mapram_mask);
512 }
513 };
514
515 // Used for array indices in allocate_all_action
516 enum RAM_side_t { LEFT = 0, RIGHT, RAM_SIDES };
517
518 safe_vector<table_alloc *> tables;
519 safe_vector<table_alloc *> exact_tables;
520 safe_vector<SRAM_group *> exact_match_ways;
521 safe_vector<table_alloc *> atcam_tables;
522 safe_vector<SRAM_group *> atcam_partitions;
523 safe_vector<table_alloc *> ternary_tables;
524 safe_vector<table_alloc *> tind_tables;
525 safe_vector<SRAM_group *> tind_groups;
526 safe_vector<table_alloc *> action_tables;
527 safe_vector<table_alloc *> indirect_action_tables;
528 safe_vector<table_alloc *> selector_tables;
529 safe_vector<table_alloc *> stats_tables;
530 safe_vector<table_alloc *> meter_tables;
531 safe_vector<table_alloc *> stateful_tables;
532 ordered_set<SRAM_group *> action_bus_users;
533 ordered_set<SRAM_group *> synth_bus_users;
534 ordered_set<const SRAM_group *> must_place_in_half;
535 safe_vector<table_alloc *> gw_tables;
536 safe_vector<table_alloc *> no_match_hit_tables;
537 safe_vector<table_alloc *> no_match_miss_tables;
538 safe_vector<table_alloc *> payload_gws;
539 safe_vector<table_alloc *> normal_gws;
540 safe_vector<table_alloc *> no_match_gws;
541 safe_vector<table_alloc *> tind_result_bus_tables;
542 safe_vector<table_alloc *> idletime_tables;
543 safe_vector<SRAM_group *> idletime_groups;
544
545 // Switchbox Related Helper functions
546 int phys_to_log_row(int physical_row, RAM_side_t side) const;
547 int log_to_phys_row(int logical_row, RAM_side_t *side = nullptr) const;
548 void determine_synth_RAMs(int &RAMs_available, int row, const SRAM_group *curr_oflow) const;
549 void determine_action_RAMs(int &RAMs_available, int row, RAM_side_t side,
550 const safe_vector<LogicalRowUser> &lrus) const;
551 bool alu_pathway_available(SRAM_group *synth_table, int row,
552 const SRAM_group *curr_oflow) const;
553 int lowest_row_to_overflow(const SRAM_group *candidate, int row) const;
554 int open_rams_between_rows(int highest_logical_row, int lowest_logical_row, bitvec sides) const;
555 int open_maprams_between_rows(int highest_phys_row, int lowest_phys_row) const;
556 bool overflow_possible(const SRAM_group *candidate, const SRAM_group *curr_oflow, int row,
557 RAM_side_t side) const;
558 bool can_be_placed_in_half(const SRAM_group *candidate, int row, RAM_side_t side,
559 const SRAM_group *synth, int RAMs_avail_on_row) const;
560 bool break_other_overflow(const SRAM_group *candidate, const SRAM_group *curr_oflow, int row,
561 RAM_side_t side) const;
562 bool satisfy_sel_swbox_constraints(const SRAM_group *candidate, const SRAM_group *sel_oflow,
563 SRAM_group *synth) const;
564 void determine_fit_on_logical_row(SRAM_group **fit_on_logical_row, SRAM_group *candidate,
565 int RAMs_avail) const;
566 void determine_max_req(SRAM_group **max_req, SRAM_group *candidate) const;
567 void candidates_for_synth_row(SRAM_group **fit_on_logical_row, SRAM_group **largest_req,
568 int row, const SRAM_group *curr_oflow,
569 const SRAM_group *sel_oflow, int RAMs_avail) const;
570 void candidates_for_action_row(SRAM_group **fit_on_logical_row, SRAM_group **largest_req,
571 int row, RAM_side_t side, const SRAM_group *curr_oflow,
572 const SRAM_group *sel_oflow, int RAMs_avail,
573 SRAM_group *synth) const;
574 void determine_synth_logical_row_users(SRAM_group *fit_on_logical_row, SRAM_group *max_req,
575 SRAM_group *curr_oflow,
576 safe_vector<LogicalRowUser> &lrus, int RAMs_avail) const;
577 bool action_candidate_prefer_sel(SRAM_group *max_req, SRAM_group *synth, SRAM_group *curr_oflow,
578 SRAM_group *sel_oflow,
579 safe_vector<LogicalRowUser> &lrus) const;
580 void determine_action_logical_row_users(SRAM_group *fit_on_logical_row, SRAM_group *max_req,
581 SRAM_group *synth, SRAM_group *curr_oflow,
582 SRAM_group *sel_oflow,
583 safe_vector<LogicalRowUser> &lrus,
584 int RAMs_avail) const;
585 void determine_RAM_masks(safe_vector<LogicalRowUser> &lrus, int row, RAM_side_t side,
586 int RAMs_available, bool is_synth_type) const;
587 void one_color_map_RAM_mask(LogicalRowUser &lru, bitvec &map_RAM_in_use, bool &stats_bus_used,
588 int row) const;
589 void determine_color_map_RAM_masks(safe_vector<LogicalRowUser> &lrus, int row) const;
590 void determine_logical_row_masks(safe_vector<LogicalRowUser> &lrus, int row, RAM_side_t side,
591 int RAMs_avaialble, bool is_synth_type) const;
592 void find_swbox_candidates(safe_vector<LogicalRowUser> &lrus, int row, RAM_side_t side,
593 SRAM_group *curr_oflow, SRAM_group *sel_oflow);
594 void fill_RAM_use(LogicalRowUser &lru, int row, RAM_side_t side);
595 void fill_color_map_RAM_use(LogicalRowUser &lru, int row);
596 void remove_placed_group(SRAM_group *candidate, RAM_side_t side);
597 void update_must_place_in_half(const SRAM_group *candidate, switchbox_t bus);
598 void fill_swbox_side(safe_vector<LogicalRowUser> &lrus, int row, RAM_side_t side);
599 void swbox_logical_row(safe_vector<LogicalRowUser> &lrus, int row, RAM_side_t side,
600 SRAM_group *curr_oflow, SRAM_group *sel_oflow);
601 void calculate_curr_oflow(safe_vector<LogicalRowUser> &lrus, SRAM_group **curr_oflow,
602 SRAM_group **synth_oflow, RAM_side_t side) const;
603 void calculate_sel_oflow(safe_vector<LogicalRowUser> &lrus, SRAM_group **sel_oflow) const;
604 // Switchbox related helper functions end
605
606 int allocation_count = 0;
607 ordered_map<const IR::MAU::AttachedMemory *, table_alloc *> shared_attached;
608 unsigned side_mask(RAM_side_t side) const;
609 unsigned partition_mask(RAM_side_t side);
610 int mems_needed(int entries, int depth, int per_mem_row, bool is_twoport);
611 void clear_table_vectors();
612 void clear_uses();
613 void clear_allocation();
614 void set_logical_memuse_type(table_alloc *ta, Use::type_t type);
615 bool analyze_tables(mem_info &mi);
616 void calculate_entries();
617 void calculate_column_balance(const mem_info &mi, unsigned &row, bool &column_balance_init);
618 bool single_allocation_balance(mem_info &mi, unsigned row);
619 bool cut_from_left_side(const mem_info &mi, int left_given_columns, int right_given_columns);
620 bool allocate_all_atcam(mem_info &mi);
621 bool allocate_all_exact(unsigned column_mask);
622 safe_vector<int> way_size_calculator(int ways, int RAMs_needed);
623 safe_vector<std::pair<int, int>> available_SRAMs_per_row(unsigned mask, SRAM_group *group,
624 int width_sect);
625 safe_vector<int> available_match_SRAMs_per_row(unsigned selected_columns_mask,
626 unsigned total_mask, std::set<int> selected_rows,
627 SRAM_group *group, int width_sect);
628 void break_exact_tables_into_ways();
629 bool search_bus_available(int search_row, search_bus_info &sbi);
630 bool result_bus_available(int match_row, result_bus_info &mbi);
631 int select_search_bus(SRAM_group *group, int width_sect, int row);
632 int select_result_bus(SRAM_group *group, int width_sect, int row);
633 bool find_best_row_and_fill_out(unsigned column_mask);
634 bool fill_out_row(SRAM_group *placed_way, int row, unsigned column_mask);
635 SRAM_group *find_best_candidate(SRAM_group *placed_way, int row, int &loc);
636 void compress_ways(bool atcam);
637 void compress_row(Use &alloc);
638
639 void break_atcams_into_partitions();
640 bool determine_match_rows_and_cols(SRAM_group *group, int row, unsigned column_mask,
641 match_selection &match_select, bool atcam);
642 void fill_out_match_alloc(SRAM_group *group, match_selection &match_select, bool atcam);
643 bool find_best_partition_for_atcam(unsigned column_mask);
644 bool fill_out_partition(int row, unsigned partition_mask);
645 unsigned best_partition_side(mem_info &mi);
646 SRAM_group *best_partition_candidate(int row, unsigned column_mask, int &loc);
647
648 bool allocate_all_ternary();
649 int ternary_TCAMs_necessary(table_alloc *ta, int &midbyte);
650 bool find_ternary_stretch(int TCAMs_necessary, int &row, int &col, int midbyte,
651 bool &split_midbyte);
652
653 bool allocate_all_tind();
654 void find_tind_groups();
655 int find_best_tind_row(SRAM_group *tg, int &bus);
656 void compress_tind_groups();
657
658 bool allocate_all_swbox_users();
659 void find_swbox_bus_users();
660 void swbox_bus_selectors_indirects();
661 void swbox_bus_meters_counters();
662 void swbox_bus_stateful_alus();
663
664 void log_allocation(safe_vector<table_alloc *> *tas, UniqueAttachedId::type_t type);
665 void log_allocation(safe_vector<table_alloc *> *tas, UniqueAttachedId::pre_placed_type_t ppt);
666 void action_bus_users_log();
667 bool find_unit_gw(Memories::Use &alloc, cstring name, bool requires_search_bus);
668 bool find_search_bus_gw(table_alloc *ta, Memories::Use &alloc, cstring name);
669 bool find_result_bus_gw(Memories::Use &alloc, uint64_t payload, cstring name,
670 table_alloc *ta_no_match, int logical_table = -1);
671 uint64_t determine_payload(table_alloc *ta);
672 bool allocate_all_gw();
673 bool allocate_all_payload_gw(bool alloc_search_bus);
674 bool allocate_all_normal_gw(bool alloc_search_bus);
675 bool allocate_all_no_match_gw();
676 table_alloc *find_corresponding_exact_match(cstring name);
677 bool gw_search_bus_fit(table_alloc *ta, table_alloc *exact_ta, int row, int col);
678 bool allocate_all_no_match_miss();
679 bool allocate_all_tind_result_bus_tables();
680
681 bool find_mem_and_bus_for_idletime(std::vector<std::pair<int, std::vector<int>>> &mem_locs,
682 int &bus, int total_mem_required, bool top_half);
683 bool allocate_idletime_in_top_or_bottom_half(SRAM_group *idletime_group, bool top_or_bottom);
684 bool allocate_idletime(SRAM_group *idletime_group);
685 bool allocate_all_idletime();
686 friend std::ostream &operator<<(std::ostream &, const safe_vector<Memories::table_alloc *> &);
687
688 public:
689 bool allocate_all() override;
690 bool allocate_all_dummies() override;
691 void update(cstring name, const Use &alloc) override;
692 void update(const std::map<UniqueId, Use> &alloc) override;
693 void remove(cstring name, const Use &alloc) override;
694 void remove(const std::map<UniqueId, Use> &alloc) override;
695 void clear() override;
696 void add_table(const IR::MAU::Table *t, const IR::MAU::Table *gw, TableResourceAlloc *resources,
697 const LayoutOption *lo, const ActionData::Format::Use *af,
698 ActionData::FormatType_t ft, int entries, int stage_table,
699 attached_entries_t attached_entries) override;
700 void shrink_allowed_lts() override { logical_tables_allowed--; }
701 void fill_placed_scm_table(const IR::MAU::Table *, const TableResourceAlloc *) override {
702 BUG("SCM Not supported on this device");
703 }
704 void printOn(std::ostream &) const override;
705 void visitUse(const Use &, std::function<void(cstring &, update_type_t)> fn) override;
706 const ordered_map<cstring, int> collect_sram_block_alloc_info() override {
707 const BFN::Alloc2Dbase<cstring> *arrays[] = {&tcam_use,
708 &sram_print_search_bus,
709 &sram_print_result_bus,
710 &tind_bus,
711 &action_data_bus,
712 &stash_use,
713 &sram_use,
714 &mapram_use,
715 &overflow_bus,
716 &gateway_use,
717 &payload_use};
718 ordered_map<cstring, int> sram_info;
719 for (auto arr : arrays)
720 for (int r = 0; r < arr->rows(); r++)
721 for (int c = 0; c < arr->cols(); c++)
722 if (arr->at(r, c))
723 // initialize all table sram block numbers to zero.
724 sram_info[arr->at(r, c)] = 0;
725
726 for (int r = 0; r < SRAM_ROWS; r++) {
727 for (int c = 0; c < SRAM_COLUMNS; c++) {
728 if (auto tbl = sram_use.at(r, c)) {
729 // count sram blocks
730 sram_info[tbl]++;
731 }
732 }
733 }
734 return sram_info;
735 }
736};
737
738} // namespace Tofino
739
740#endif /* BF_P4C_MAU_TOFINO_MEMORIES_H_ */
Definition attached_info.h:32
Definition alloc.h:65
Definition alloc.h:152
Definition table_layout.h:34
Definition stringify.h:33
Definition unique_id.h:168
Definition cstring.h:85
Definition ordered_set.h:32
Definition safe_vector.h:27
Definition tofino/action_data_bus.cpp:28
Definition action_format.h:979
Definition instruction_memory.h:111
Definition table_format.h:108
Definition tofino/memories.h:317
Definition tofino/memories.h:337
Definition tofino/memories.h:37