P4C
The P4 Compiler
Loading...
Searching...
No Matches
tables.h
1
17
18#ifndef BACKENDS_TOFINO_BF_ASM_TABLES_H_
19#define BACKENDS_TOFINO_BF_ASM_TABLES_H_
20
21#include <iostream>
22#include <set>
23#include <string>
24#include <unordered_map>
25#include <vector>
26
27#include "backends/tofino/bf-asm/alloc.h"
28#include "backends/tofino/bf-asm/asm-types.h"
29#include "backends/tofino/bf-asm/config.h"
30#include "backends/tofino/bf-asm/json.h"
31#include "backends/tofino/bf-asm/map.h"
32#include "backends/tofino/bf-asm/p4_table.h"
33#include "backends/tofino/bf-asm/phv.h"
34#include "backends/tofino/bf-asm/slist.h"
35#include "backends/tofino/bf-asm/target.h"
36#include "constants.h"
37#include "hash_dist.h"
38#include "input_xbar.h"
39#include "lib/algorithm.h"
40#include "lib/bitops.h"
41#include "lib/bitvec.h"
42#include "lib/ordered_map.h"
43
44class ActionBus;
45struct ActionBusSource;
46class AttachedTable;
47struct AttachedTables;
48class GatewayTable;
49class IdletimeTable;
50class ActionTable;
51struct Instruction;
52class InputXbar;
53class MatchTable;
54class SelectionTable;
55class StatefulTable;
56class MeterTable;
57class Synth2Port;
58class Stage;
59struct HashCol;
60
61struct RandomNumberGen {
62 int unit;
63 explicit RandomNumberGen(int u) : unit(u) {}
64 bool operator==(const RandomNumberGen &a) const { return unit == a.unit; }
65};
66
67enum class TableOutputModifier { NONE, Color, Address };
68std::ostream &operator<<(std::ostream &, TableOutputModifier);
69
70/* a memory storage 'unit' somewhere on the chip */
71struct MemUnit {
72 int stage = INT_MIN; // current stage (only) for tofino1/2
73 // can have negative stage numbers for tcams in egress
74 int row = -1;
75 int col; // (lamb) unit when row == -1
76 MemUnit() = delete;
77 MemUnit(const MemUnit &) = default;
78 MemUnit(MemUnit &&) = default;
79 MemUnit &operator=(const MemUnit &) = default;
80 MemUnit &operator=(MemUnit &&) = default;
81 virtual ~MemUnit() {}
82 explicit MemUnit(int unit) : col(unit) {}
83 MemUnit(int r, int c) : row(r), col(c) {}
84 MemUnit(int s, int r, int c) : stage(s), row(r), col(c) {}
85 bool operator==(const MemUnit &a) const {
86 return std::tie(stage, row, col) == std::tie(a.stage, a.row, a.col);
87 }
88 bool operator!=(const MemUnit &a) const {
89 return std::tie(stage, row, col) != std::tie(a.stage, a.row, a.col);
90 }
91 bool operator<(const MemUnit &a) const {
92 return std::tie(stage, row, col) < std::tie(a.stage, a.row, a.col);
93 }
94 virtual const char *desc() const; // Short lived temp for messages
95 friend std::ostream &operator<<(std::ostream &out, const MemUnit &m) { return out << m.desc(); }
96};
97
98class Table {
99 public:
100 struct Layout {
101 /* Holds the layout of which rams/tcams/busses are used by the table
102 * These refer to rows/columns in different spaces:
103 * ternary match refers to tcams (12x2)
104 * exact match and ternary indirect refer to physical srams (8x12)
105 * action (and others?) refer to logical srams (16x6)
106 * vpns contains the (base)vpn index of each ram in the row
107 * maprams contain the map ram indexes for synthetic 2-port memories
108 * vpns/maprams (if not empty) must match up to memunits (same size) */
109 int lineno = -1;
110 int row = -1;
111 enum bus_type_t { SEARCH_BUS, RESULT_BUS, TIND_BUS, IDLE_BUS, L2R_BUS, R2L_BUS };
112 std::map<bus_type_t, int> bus;
113
114 int word = -1; // which word for wide tables
115 bool home_row = false; // is this a home row
116 std::vector<MemUnit> memunits;
117 std::vector<int> vpns, maprams;
118 Layout() = default;
119 Layout(int l, int r) : lineno(l), row(r) {}
120 friend std::ostream &operator<<(std::ostream &, const Layout &);
121
122 bool word_initialized() const { return word >= 0; }
123 bool operator==(const Layout &) const;
124 bool operator!=(const Layout &a) const { return !(*this == a); }
125 };
126
127 protected:
128 Table(int line, std::string &&n, gress_t gr, Stage *s,
129 int lid = -1); // NOLINT(whitespace/operators)
130 virtual ~Table();
131 Table(const Table &) = delete;
132 Table(Table &&) = delete;
133 virtual void setup(VECTOR(pair_t) & data) = 0;
134 virtual void common_init_setup(const VECTOR(pair_t) &, bool, P4Table::type);
135 virtual bool common_setup(pair_t &, const VECTOR(pair_t) &, P4Table::type);
136 void setup_context_json(value_t &);
137 void setup_layout(std::vector<Layout> &, const VECTOR(pair_t) & data, const char *subname = "");
138 int setup_layout_bus_attrib(std::vector<Layout> &, const value_t &data, const char *what,
139 Layout::bus_type_t type);
140 int setup_layout_attrib(std::vector<Layout> &, const value_t &data, const char *what,
141 int Layout::*attr);
142 void setup_logical_id();
143 void setup_actions(value_t &);
144 void setup_maprams(value_t &);
145 void setup_vpns(std::vector<Layout> &, VECTOR(value_t) *, bool allow_holes = false);
146 virtual void vpn_params(int &width, int &depth, int &period, const char *&period_name) const {
147 BUG("unsupported");
148 }
149 virtual int get_start_vpn() { return 0; }
150 void alloc_rams(bool logical, BFN::Alloc2Dbase<Table *> &use,
151 BFN::Alloc2Dbase<Table *> *bus_use = 0,
152 Layout::bus_type_t bus_type = Layout::SEARCH_BUS);
153 void alloc_global_bus(Layout &, Layout::bus_type_t, int, int, int, int);
154 virtual void alloc_global_busses();
155 void alloc_global_srams();
156 void alloc_global_tcams();
157 void alloc_busses(BFN::Alloc2Dbase<Table *> &bus_use, Layout::bus_type_t bus_type);
158 void alloc_id(const char *idname, int &id, int &next_id, int max_id, bool order,
159 BFN::Alloc1Dbase<Table *> &use);
160 void alloc_maprams();
161 virtual void alloc_vpns();
162 virtual Layout::bus_type_t default_bus_type() const { return Layout::SEARCH_BUS; }
163 void need_bus(int lineno, BFN::Alloc1Dbase<Table *> &use, int idx, const char *name);
164 static bool allow_ram_sharing(const Table *t1, const Table *t2);
165
166 public:
167 class Type {
168 static std::map<std::string, Type *> *all;
169 std::map<std::string, Type *>::iterator self;
170
171 protected:
172 explicit Type(std::string &&); // NOLINT(whitespace/operators)
173 explicit Type(const char *name) : Type(std::string(name)) {}
174 virtual ~Type();
175
176 public:
177 static Type *get(const char *name) { return ::get(all, name); }
178 static Type *get(const std::string &name) { return ::get(all, name); }
179 virtual Table *create(int lineno, const char *name, gress_t gress, Stage *stage, int lid,
180 VECTOR(pair_t) & data) = 0;
181 };
182
183 struct Ref {
184 int lineno;
185 std::string name;
186 Ref() : lineno(-1) {}
187 Ref(const Ref &) = default;
188 Ref(Ref &&) = default;
189 Ref &operator=(const Ref &a) & {
190 name = a.name;
191 if (lineno < 0) lineno = a.lineno;
192 return *this;
193 }
194 Ref &operator=(Ref &&a) & {
195 name = a.name;
196 if (lineno < 0) lineno = a.lineno;
197 return *this;
198 }
199 Ref &operator=(const value_t &a) & {
200 BUG_CHECK(a.type == tSTR, "expected string");
201 name = a.s;
202 lineno = a.lineno;
203 return *this;
204 }
205 Ref(const std::string &n) : lineno(-1), name(n) {} // NOLINT(runtime/explicit)
206 Ref(const char *n) : lineno(-1), name(n) {} // NOLINT(runtime/explicit)
207 Ref(const value_t &a) : lineno(a.lineno) { // NOLINT(runtime/explicit)
208 if (CHECKTYPE(a, tSTR)) name = a.s;
209 }
210 Ref &operator=(const std::string &n) {
211 name = n;
212 return *this;
213 }
214 operator bool() const { return all && all->count(name) > 0; }
215 operator Table *() const { return ::get(all, name); }
216 Table *operator->() const { return ::get(all, name); }
217 [[nodiscard]] bool set() const { return lineno >= 0; }
218 bool operator==(const Table &t) const { return name == t.name_; }
219 bool operator!=(const Table &t) const { return name != t.name_; }
220 bool operator==(const Ref &a) const { return name == a.name; }
221 bool operator!=(const Ref &a) const { return name != a.name; }
222 bool operator<(const Ref &a) const { return name < a.name; }
223 bool check() const {
224 if (set() && !*this) error(lineno, "No table named %s", name.c_str());
225 return *this;
226 }
227 };
228
229 class NextTables {
230 std::set<Ref> next;
231 unsigned lb_tags = 0; // long branch tags to use (bitmask)
232 const Table *next_table_ = nullptr; // table to use as next table (if any)
233 bool resolved = false;
234 bool can_use_lb(int stage, const NextTables &);
235
236 public:
237 int lineno = -1;
238 NextTables() = default;
239 NextTables(const NextTables &) = default;
240 NextTables(NextTables &&) = default;
241 NextTables &operator=(const NextTables &a) = default;
242 NextTables &operator=(NextTables &&) = default;
243 NextTables(value_t &v); // NOLINT(runtime/explicit)
244
245 std::set<Ref>::iterator begin() const { return next.begin(); }
246 std::set<Ref>::iterator end() const { return next.end(); }
247 int size() const { return next.size(); }
248 bool operator==(const NextTables &a) const { return next == a.next; }
249 bool subset_of(const NextTables &a) const {
250 for (auto &n : next)
251 if (!a.next.count(n)) return false;
252 return true;
253 }
254 void resolve_long_branch(const Table *tbl, const std::map<int, NextTables> &lbrch);
255 bool set() const { return lineno >= 0; }
256 int next_table_id() const {
257 BUG_CHECK(resolved, "next table not resolved");
258 return next_table_ ? next_table_->table_id() : Target::END_OF_PIPE();
259 }
260 std::string next_table_name() const {
261 BUG_CHECK(resolved, "next table not resolved");
262 if (next_table_) {
263 if (auto nxt_p4_name = next_table_->p4_name()) return nxt_p4_name;
264 }
265 return "END";
266 }
267 const Table *next_table() const { return next_table_; }
268 unsigned long_branch_tags() const { return lb_tags; }
269 unsigned next_in_stage(int stage) const;
270 bool need_next_map_lut() const;
271 void force_single_next_table();
272 };
273
274 class Format {
275 public:
276 struct bitrange_t {
277 unsigned lo, hi;
278 bitrange_t(unsigned l, unsigned h) : lo(l), hi(h) {}
279 bool operator==(const bitrange_t &a) const { return lo == a.lo && hi == a.hi; }
280 bool disjoint(const bitrange_t &a) const { return lo > a.hi || a.lo > hi; }
281 bitrange_t overlap(const bitrange_t &a) const {
282 // only valid if !disjoint
283 return bitrange_t(std::max(lo, a.lo), std::min(hi, a.hi));
284 }
285 int size() const { return hi - lo + 1; }
286 };
287 struct Field {
288 unsigned size = 0, group = 0, flags = 0;
289 std::vector<bitrange_t> bits;
290 Field **by_group = 0;
291 Format *fmt; // containing format
292 bool operator==(const Field &a) const { return size == a.size; }
293 /* return the bit in the format that contains bit i of this field */
294 unsigned bit(unsigned i) {
295 unsigned last = 0;
296 for (auto &chunk : bits) {
297 if (i < (unsigned)chunk.size()) return chunk.lo + i;
298 i -= chunk.size();
299 last = chunk.hi + 1;
300 }
301 if (i == 0) return last;
302 BUG("unsupported");
303 return 0; // quiet -Wreturn-type warning
304 }
305 /* bit(i), adjusted for the immediate shift of the match group of the field
306 * returns the bit in the post-extract immediate containing bit i */
307 unsigned immed_bit(unsigned i) {
308 auto rv = bit(i);
309 if (fmt && fmt->immed) rv -= fmt->immed->by_group[group]->bit(0);
310 return rv;
311 }
312 unsigned hi(unsigned bit) {
313 for (auto &chunk : bits)
314 if (bit >= chunk.lo && bit <= chunk.hi) return chunk.hi;
315 BUG("unsupported");
316 return 0; // quiet -Wreturn-type warning
317 }
318 enum flags_t { NONE = 0, USED_IMMED = 1, ZERO = 3 };
319 bool conditional_value = false;
320 std::string condition;
321 explicit Field(Format *f) : fmt(f) {}
322 Field(Format *f, unsigned size, unsigned lo = 0, enum flags_t fl = NONE)
323 : size(size), flags(fl), fmt(f) {
324 if (size) bits.push_back({lo, lo + size - 1});
325 }
326 Field(const Field &f, Format *fmt)
327 : size(f.size), flags(f.flags), bits(f.bits), fmt(fmt) {}
328
330 void set_field_bits(bitvec &bitset) const {
331 for (auto &b : bits) bitset.setrange(b.lo, b.size());
332 }
333 };
334 friend std::ostream &operator<<(std::ostream &, const Field &);
335 explicit Format(Table *t) : tbl(t) { fmt.resize(1); }
336 Format(Table *, const VECTOR(pair_t) & data, bool may_overlap = false);
337 ~Format();
338 void pass1(Table *tbl);
339 void pass2(Table *tbl);
340
341 private:
342 std::vector<ordered_map<std::string, Field>> fmt;
343 std::map<unsigned, ordered_map<std::string, Field>::iterator> byindex;
344 static bool equiv(const ordered_map<std::string, Field> &,
346
347 public:
348 int lineno = -1;
349 Table *tbl;
350 unsigned size = 0, immed_size = 0;
351 Field *immed = 0;
352 unsigned log2size = 0; /* ceil(log2(size)) */
353 unsigned overhead_start = 0, overhead_size = 0; // extent of non-match
354 int overhead_word = -1;
355
356 unsigned groups() const { return fmt.size(); }
357 const ordered_map<std::string, Field> &group(int g) const { return fmt.at(g); }
358 Field *field(const std::string &n, int group = 0) {
359 BUG_CHECK(group >= 0 && (size_t)group < fmt.size(), "invalid group %d", group);
360 auto it = fmt[group].find(n);
361 if (it != fmt[group].end()) return &it->second;
362 return 0;
363 }
364 void apply_to_field(const std::string &n, std::function<void(Field *)> fn) {
365 for (auto &m : fmt) {
366 auto it = m.find(n);
367 if (it != m.end()) fn(&it->second);
368 }
369 }
370 std::string find_field(Field *field) {
371 for (auto &m : fmt)
372 for (auto &f : m)
373 if (field == &f.second) return f.first;
374 return "<unknown>";
375 }
376 int find_field_lineno(Field *field) {
377 for (auto &m : fmt)
378 for (auto &f : m)
379 if (field == &f.second) return lineno;
380 return -1;
381 }
382 void add_field(Field &f, std::string name = "dummy", int grp = 0) {
383 fmt[grp].emplace(name, Field(f, this));
384 }
385 decltype(fmt[0].begin()) begin(int grp = 0) { return fmt[grp].begin(); }
386 decltype(fmt[0].end()) end(int grp = 0) { return fmt[grp].end(); }
387 decltype(fmt[0].cbegin()) begin(int grp = 0) const { return fmt[grp].begin(); }
388 decltype(fmt[0].cend()) end(int grp = 0) const { return fmt[grp].end(); }
389 bool is_wide_format() const { return (log2size >= 7 || groups() > 1) ? true : false; }
390 int get_entries_per_table_word() const {
391 // A phase0 table can only have 1 entry
392 if (tbl->table_type() == PHASE0) return 1;
393 if (is_wide_format()) return groups();
394 return log2size ? (1U << (ceil_log2(tbl->ram_word_width()) - log2size)) : 0;
395 }
396 int get_mem_units_per_table_word() const {
397 return is_wide_format() ? ((size - 1) / tbl->ram_word_width()) + 1 : 1;
398 }
399 int get_table_word_width() const {
400 return is_wide_format() ? tbl->ram_word_width() * get_mem_units_per_table_word()
401 : tbl->ram_word_width();
402 }
403 int get_padding_format_width() const {
404 return is_wide_format() ? get_mem_units_per_table_word() * tbl->ram_word_width()
405 : (1U << log2size);
406 }
407 };
408
409 struct Call : Ref { /* a Ref with arguments */
410 struct Arg {
411 enum { Field, HashDist, Counter, Const, Name } type;
412
413 private:
414 union {
415 Format::Field *fld;
417 intptr_t val;
418 char *str;
419 };
420
421 void set(const Arg &a) {
422 type = a.type;
423 switch (type) {
424 case Field:
425 fld = a.fld;
426 return;
427 case HashDist:
428 hd = a.hd;
429 return;
430 case Counter:
431 case Const:
432 val = a.val;
433 return;
434 case Name:
435 str = a.str;
436 return;
437 }
438 }
439
440 public:
441 Arg() = delete;
442 Arg(const Arg &a) {
443 set(a);
444 if (type == Name) str = strdup(str);
445 }
446 Arg(Arg &&a) {
447 set(a);
448 a.type = Const;
449 }
450 Arg &operator=(const Arg &a) {
451 if (&a == this) return *this;
452 if (a == *this) return *this;
453 if (type == Name) free(str);
454 set(a);
455 if (type == Name) str = strdup(a.str);
456 return *this;
457 }
458 Arg &operator=(Arg &&a) {
459 std::swap(type, a.type);
460 std::swap(val, a.val);
461 return *this;
462 }
463 Arg(Format::Field *f) : type(Field) { fld = f; } // NOLINT(runtime/explicit)
464 Arg(HashDistribution *hdist) : type(HashDist) { // NOLINT(runtime/explicit)
465 hd = hdist;
466 }
467 Arg(int v) : type(Const) { val = v; } // NOLINT(runtime/explicit)
468 Arg(const char *n) : type(Name) { str = strdup(n); } // NOLINT(runtime/explicit)
469 Arg(decltype(Counter) ctr, int mode) : type(Counter) {
470 val = mode;
471 BUG_CHECK(ctr == Counter, "invalid counter type");
472 }
473 ~Arg() {
474 if (type == Name) free(str);
475 }
476 bool operator==(const Arg &a) const {
477 if (type != a.type) return false;
478 switch (type) {
479 case Field:
480 return fld == a.fld;
481 case HashDist:
482 return hd == a.hd;
483 case Counter:
484 case Const:
485 return val == a.val;
486 case Name:
487 return !strcmp(str, a.str);
488 default:
489 BUG("unknown argument type");
490 }
491 return false;
492 }
493 bool operator!=(const Arg &a) const { return !operator==(a); }
494 Format::Field *field() const { return type == Field ? fld : nullptr; }
495 HashDistribution *hash_dist() const { return type == HashDist ? hd : nullptr; }
496 const char *name() const { return type == Name ? str : nullptr; }
497 int count_mode() const { return type == Counter ? val : 0; }
498 int value() const { return type == Const ? val : 0; }
499 operator bool() const { return fld != nullptr; }
500 unsigned size() const;
501 };
502 std::vector<Arg> args;
503 void setup(const value_t &v, Table *tbl);
504 Call() {}
505 Call(const value_t &v, Table *tbl) { setup(v, tbl); }
506 bool operator==(const Call &a) const { return Ref::operator==(a) && args == a.args; }
507 bool operator!=(const Call &a) const { return !(*this == a); }
508 bool is_direct_call() const {
509 if (args.size() == 0) return false;
510 for (auto &a : args)
511 if (a == "$DIRECT") return true;
512 return false;
513 }
514 };
515
516 struct p4_param {
517 std::string name;
518 std::string alias;
519 std::string key_name;
520 unsigned start_bit = 0;
521 unsigned position = 0;
522 unsigned bit_width = 0;
523 unsigned bit_width_full = 0;
524 bitvec mask;
525 std::string default_value; // value stored as hex string to accommodate large nos
526 bool defaulted = false;
527 bool is_valid = false;
528 std::string type;
529 std::unique_ptr<json::map> context_json;
530 explicit p4_param(std::string n = "", unsigned p = 0, unsigned bw = 0)
531 : name(n), position(p), bit_width(bw) {}
532 };
533 friend std::ostream &operator<<(std::ostream &, const p4_param &);
534 typedef std::vector<p4_param> p4_params;
535
536 class Actions {
537 public:
538 struct Action {
539 struct alias_t {
540 std::string name;
541 int lineno = -1, lo = -1, hi = -1;
542 bool is_constant = false;
543 unsigned value = 0;
544 explicit alias_t(value_t &);
545 unsigned size() const {
546 if (hi != -1 && lo != -1)
547 return hi - lo + 1;
548 else
549 return 0;
550 }
551 std::string to_string() const {
552 if (hi >= 0 && lo >= 0)
553 return name + '(' + std::to_string(lo) + ".." + std::to_string(hi) + ')';
554 return name;
555 }
556 };
557 std::string name;
558 std::string rng_param_name = "";
559 int lineno = -1, addr = -1, code = -1;
560 std::multimap<std::string, alias_t> alias;
561 std::vector<std::unique_ptr<Instruction>> instr;
562 bitvec slot_use;
563 unsigned handle = 0;
564 p4_params p4_params_list;
565 bool hit_allowed = true;
566 bool default_allowed = false;
567 bool default_only = false;
568 bool is_constant = false;
569 std::string hit_disallowed_reason = "";
570 std::string default_disallowed_reason = "";
571 std::vector<Call> attached;
572 int next_table_encode = -1;
573 NextTables next_table_ref;
574 NextTables next_table_miss_ref;
575 std::map<std::string, std::vector<bitvec>> mod_cond_values;
576 // The hit map points to next tables for actions as ordered in the
577 // assembly, we use 'position_in_assembly' to map the correct next
578 // table, as actions can be ordered in the map different from the
579 // assembly order.
580 int position_in_assembly = -1;
581 bool minmax_use = false; // jbay sful min/max
582 // Predication operand coming into the output ALUs in stateful actions. This attribute
583 // is used to make sure that all combined predicate outputs from a given stateful action
584 // have the same form, because the predication operand is always the same in every
585 // output ALU.
586 int pred_comb_sel = -1;
587 std::unique_ptr<json::map> context_json;
588 Action(Table *, Actions *, pair_t &, int);
589 enum mod_cond_loc_t { MC_ADT, MC_IMMED };
591 Action(const char *n, int l);
592 Action(const Action &) = delete;
593 Action(Action &&) = delete;
594 ~Action();
595 bool equiv(Action *a);
596 bool equivVLIW(Action *a);
597 typedef const decltype(alias)::value_type alias_value_t;
598 std::map<std::string, std::vector<alias_value_t *>> reverse_alias() const;
599 std::string alias_lookup(int lineno, std::string name, int &lo, int &hi) const;
600 bool has_rng() { return !rng_param_name.empty(); }
601 const p4_param *has_param(std::string param) const {
602 for (auto &e : p4_params_list)
603 if (e.name == param) return &e;
604 return nullptr;
605 }
606 void pass1(Table *tbl);
607 void check_next(Table *tbl);
608 void check_next_ref(Table *tbl, const Table::Ref &ref) const;
609 void add_direct_resources(json::vector &direct_resources, const Call &att) const;
610 void add_indirect_resources(json::vector &indirect_resources, const Call &att) const;
611 void check_and_add_resource(json::vector &resources, json::map &resource) const;
612 bool is_color_aware() const;
613 void gen_simple_tbl_cfg(json::vector &) const;
614 void add_p4_params(json::vector &, bool include_default = true) const;
615 void check_conditional(Table::Format::Field &field) const;
616 bool immediate_conditional(int lo, int sz, std::string &condition) const;
617 friend std::ostream &operator<<(std::ostream &, const alias_t &);
618 friend std::ostream &operator<<(std::ostream &, const Action &);
619 };
620
621 private:
622 typedef ordered_map<std::string, Action> map_t;
623 map_t actions;
624 bitvec code_use;
625 std::map<int, Action *> by_code;
626 bitvec slot_use;
627 Table *table;
628
629 public:
630 int max_code = -1;
631 Actions(Table *tbl, VECTOR(pair_t) &);
632 typedef map_t::value_type value_type;
633 typedef IterValues<map_t::iterator>::iterator iterator;
634 typedef IterValues<map_t::const_iterator>::iterator const_iterator;
635 iterator begin() { return iterator(actions.begin()); }
636 const_iterator begin() const { return const_iterator(actions.begin()); }
637 iterator end() { return iterator(actions.end()); }
638 const_iterator end() const { return const_iterator(actions.end()); }
639 int count() { return actions.size(); }
640 int hit_actions_count() const;
641 int default_actions_count() const;
642 Action *action(const std::string &n) {
643 auto it = actions.find(n);
644 return it == actions.end() ? nullptr : &it->second;
645 }
646 bool exists(const std::string &n) { return actions.count(n) > 0; }
647 void pass1(Table *);
648 void pass2(Table *);
649 void stateful_pass2(Table *);
650 template <class REGS>
651 void write_regs(REGS &, Table *);
652 void add_p4_params(const Action &, json::vector &) const;
653 void gen_tbl_cfg(json::vector &) const;
654 void add_immediate_mapping(json::map &);
655 void add_action_format(const Table *, json::map &) const;
656 bool has_hash_dist() { return (table->table_type() == HASH_ACTION); }
657 size_t size() { return actions.size(); }
658 };
659
660 public:
661 const char *name() const { return name_.c_str(); }
662 const char *p4_name() const {
663 if (p4_table) {
664 return p4_table->p4_name();
665 }
666 return nullptr;
667 }
668 unsigned p4_size() const {
669 if (p4_table) {
670 return p4_table->p4_size();
671 }
672 return 0;
673 }
674 unsigned handle() const {
675 if (p4_table) {
676 return p4_table->get_handle();
677 }
678 return -1;
679 }
680 std::string action_profile() const {
681 if (p4_table) {
682 return p4_table->action_profile;
683 }
684 return "";
685 }
686 std::string how_referenced() const {
687 if (p4_table) {
688 return p4_table->how_referenced;
689 }
690 return "";
691 }
692 int table_id() const;
693 virtual bool is_always_run() const { return false; }
694 virtual void pass0() {} // only match tables need pass0
695 virtual void pass1();
696 virtual void pass2() = 0;
697 virtual void pass3() = 0;
698 /* C++ does not allow virtual template methods, so we work around it by explicitly
699 * instantiating overloads for all the virtual template methods we want. */
700 FOR_ALL_REGISTER_SETS(TARGET_OVERLOAD, virtual void write_action_regs,
701 (mau_regs &, const Actions::Action *), {})
702 FOR_ALL_REGISTER_SETS(TARGET_OVERLOAD, virtual void write_merge_regs,
703 (mau_regs &, int type, int bus), { assert(0); })
704 FOR_ALL_REGISTER_SETS(TARGET_OVERLOAD, virtual void write_merge_regs,
705 (mau_regs &, MatchTable *match, int type, int bus,
706 const std::vector<Call::Arg> &args),
707 { assert(0); })
708 FOR_ALL_REGISTER_SETS(TARGET_OVERLOAD, virtual void write_regs, (mau_regs &), = 0)
709
710 virtual void gen_tbl_cfg(json::vector &out) const = 0;
711 virtual json::map *base_tbl_cfg(json::vector &out, const char *type, int size) const;
712 virtual json::map *add_stage_tbl_cfg(json::map &tbl, const char *type, int size) const;
713 virtual std::unique_ptr<json::map> gen_memory_resource_allocation_tbl_cfg(
714 const char *type, const std::vector<Layout> &layout, bool skip_spare_bank = false) const;
715 virtual std::vector<int> determine_spare_bank_memory_units() const { return {}; }
716 virtual void common_tbl_cfg(json::map &tbl) const;
717 void add_match_key_cfg(json::map &tbl) const;
718 bool add_json_node_to_table(json::map &tbl, const char *name, bool append = false) const;
719 void allocate_physical_ids(unsigned usable = ~0U);
720 template <typename T>
721 void init_json_node(json::map &tbl, const char *name) const;
722 enum table_type_t {
723 OTHER = 0,
724 TERNARY_INDIRECT,
725 GATEWAY,
726 ACTION,
727 SELECTION,
728 COUNTER,
729 METER,
730 IDLETIME,
731 STATEFUL,
732 HASH_ACTION,
733 EXACT,
734 TERNARY,
735 PHASE0,
736 ATCAM,
737 PROXY_HASH
738 };
739 virtual table_type_t table_type() const { return OTHER; }
740 virtual int instruction_set() { return 0; /* VLIW_ALU */ }
741 virtual table_type_t set_match_table(MatchTable *m, bool indirect) {
742 assert(0);
743 return OTHER;
744 }
745 virtual const MatchTable *get_match_table() const {
746 assert(0);
747 return nullptr;
748 }
749 virtual MatchTable *get_match_table() {
750 assert(0);
751 return nullptr;
752 }
753 virtual std::set<MatchTable *> get_match_tables() { return std::set<MatchTable *>(); }
754 virtual const AttachedTables *get_attached() const { return 0; }
755 virtual AttachedTables *get_attached() { return 0; }
756 virtual const GatewayTable *get_gateway() const { return 0; }
757 virtual SelectionTable *get_selector() const { return 0; }
758 virtual MeterTable *get_meter() const { return 0; }
759 virtual void set_stateful(StatefulTable *s) { BUG("unsupported"); }
760 virtual StatefulTable *get_stateful() const { return 0; }
761 virtual void set_address_used() {
762 // FIXME -- could use better error message(s) -- lineno is not accurate/useful
763 error(lineno,
764 "Tofino does not support extracting the address used on "
765 "a non-stateful table %s",
766 name());
767 }
768 virtual void set_color_used() {
769 error(lineno, "Cannot extract color on a non-meter table %s", name());
770 }
771 virtual void set_output_used() {
772 error(lineno, "Cannot extract output on a non-stateful table %s", name());
773 }
774 virtual const Call &get_action() const { return action; }
775 virtual std::vector<Call> get_calls() const;
776 virtual bool is_attached(const Table *) const {
777 BUG("unsupported");
778 return false;
779 }
780 virtual Format::Field *find_address_field(const AttachedTable *) const {
781 BUG("unsupported");
782 return 0;
783 }
784 virtual Format::Field *get_per_flow_enable_param(MatchTable *) const {
785 BUG("unsupported");
786 return 0;
787 }
788 virtual Format::Field *get_meter_address_param(MatchTable *) const {
789 BUG("unsupported");
790 return 0;
791 }
792 virtual Format::Field *get_meter_type_param(MatchTable *) const {
793 BUG("unsupported");
794 return 0;
795 }
796 virtual int direct_shiftcount() const {
797 BUG("unsupported");
798 return -1;
799 }
800 virtual int indirect_shiftcount() const {
801 BUG("unsupported");
802 return -1;
803 }
804 virtual int address_shift() const {
805 BUG("unsupported");
806 return -1;
807 }
808 virtual int home_row() const {
809 BUG("unsupported");
810 return -1;
811 }
812 /* mem unitno mapping -- unit numbers used in context json */
813 virtual int json_memunit(const MemUnit &u) const;
814 virtual int ram_word_width() const { return MEM_WORD_WIDTH; }
815 virtual int unitram_type() {
816 BUG("unsupported");
817 return -1;
818 }
819 virtual bool uses_colormaprams() const { return false; }
820 virtual int color_shiftcount(Table::Call &call, int group, int tcam_shift) const {
821 BUG("unsupported");
822 return -1;
823 }
824 virtual bool adr_mux_select_stats() { return false; }
825 virtual bool run_at_eop() { return false; }
826 virtual Format *get_format() const { return format.get(); }
827 virtual unsigned determine_shiftcount(Table::Call &call, int group, unsigned word,
828 int tcam_shift) const {
829 assert(0);
830 return -1;
831 }
832 template <class REGS>
833 void write_mapram_regs(REGS &regs, int row, int col, int vpn, int type);
834 template <class T>
835 T *to() {
836 return dynamic_cast<T *>(this);
837 }
838 template <class T>
839 const T *to() const {
840 return dynamic_cast<const T *>(this);
841 }
842 virtual void determine_word_and_result_bus() { BUG("unsupported"); }
843 virtual int stm_vbus_column() const { BUG("unsupported"); }
844
845 std::string name_;
846 int uid;
847 P4Table *p4_table = 0;
848 Stage *stage = 0;
849 gress_t gress;
850 int lineno = -1;
851 int logical_id = -1;
852 bitvec physical_ids;
853 std::vector<DynamicIXbar> dynamic_config;
854 std::vector<std::unique_ptr<InputXbar>> input_xbar;
855 std::vector<Layout> layout;
856 bool no_vpns = false; // for odd actions with null vpns
857 // generated by compiler
858 std::unique_ptr<Format> format;
859 int action_enable = -1;
860 bool enable_action_data_enable = false;
861 bool enable_action_instruction_enable = false;
862 Call action;
863 Call instruction;
864 std::unique_ptr<Actions> actions;
865 std::unique_ptr<ActionBus> action_bus;
866 std::string default_action;
867 unsigned default_action_handle = 0;
868 int default_action_lineno = -1;
869 typedef std::map<std::string, std::string> default_action_params;
870 default_action_params default_action_parameters;
871 bool default_only_action = false;
872 std::vector<NextTables> hit_next;
873 std::vector<NextTables> extra_next_lut; // extra entries not in the hit_next from gateway
874 // currently the assembler will add extra elements to the 8 entry next table lut if they
875 // are needed for a gateway and not present in the lut already. We add these in a separate
876 // vector from hit_next so that context.json only reports the original hit_next from the source
877 // and we don't try to get a next table hit index from the action.
878 NextTables miss_next;
879 std::map<int, NextTables> long_branch;
880 int long_branch_input = -1;
881 std::map<Table *, std::set<Actions::Action *>> pred; // predecessor tables w the actions in
882 // that table that call this table
883 std::vector<HashDistribution> hash_dist;
884 p4_params p4_params_list;
885 std::unique_ptr<json::map> context_json;
886 // saved here in to extract into the context json
887 unsigned next_table_adr_mask = 0U;
888 bitvec reachable_tables_;
889
890 static std::map<std::string, Table *> *all;
891 static std::vector<Table *> *by_uid;
892
893 unsigned layout_size() const {
894 unsigned rv = 0;
895 for (auto &row : layout) rv += row.memunits.size();
896 return rv;
897 }
898 unsigned layout_get_vpn(const MemUnit &m) const {
899 for (auto &row : layout) {
900 if (row.row != m.row) continue;
901 auto u = find(row.memunits.begin(), row.memunits.end(), m);
902 if (u == row.memunits.end()) continue;
903 return row.vpns.at(u - row.memunits.begin());
904 }
905 BUG("unsupported");
906 return 0;
907 }
908 void layout_vpn_bounds(int &min, int &max, bool spare = false) const {
909 min = 1000000;
910 max = -1;
911 for (const Layout &row : layout)
912 for (const auto v : row.vpns) {
913 if (v < min) min = v;
914 if (v > max) max = v;
915 }
916 if (spare && max > min) --max;
917 }
918 virtual Format::Field *lookup_field(const std::string &n, const std::string &act = "") const {
919 return format ? format->field(n) : 0;
920 }
921 virtual std::string find_field(Format::Field *field) {
922 return format ? format->find_field(field) : "<unknown>";
923 }
924 virtual int find_field_lineno(Format::Field *field) {
925 return format ? format->find_field_lineno(field) : -1;
926 }
927 virtual void apply_to_field(const std::string &n, std::function<void(Format::Field *)> fn) {
928 if (format) format->apply_to_field(n, fn);
929 }
930 int find_on_ixbar(Phv::Slice sl, InputXbar::Group group, InputXbar::Group *found = nullptr);
931 int find_on_ixbar(Phv::Slice sl, int group) {
932 return find_on_ixbar(sl, InputXbar::Group(InputXbar::Group::EXACT, group));
933 }
934 virtual HashDistribution *find_hash_dist(int unit);
935 virtual int find_on_actionbus(const ActionBusSource &src, int lo, int hi, int size,
936 int pos = -1);
937 virtual void need_on_actionbus(const ActionBusSource &src, int lo, int hi, int size);
938 virtual int find_on_actionbus(const char *n, TableOutputModifier mod, int lo, int hi, int size,
939 int *len = 0);
940 int find_on_actionbus(const char *n, int lo, int hi, int size, int *len = 0) {
941 return find_on_actionbus(n, TableOutputModifier::NONE, lo, hi, size, len);
942 }
943 int find_on_actionbus(const std::string &n, TableOutputModifier mod, int lo, int hi, int size,
944 int *len = 0) {
945 return find_on_actionbus(n.c_str(), mod, lo, hi, size, len);
946 }
947 int find_on_actionbus(const std::string &n, int lo, int hi, int size, int *len = 0) {
948 return find_on_actionbus(n.c_str(), TableOutputModifier::NONE, lo, hi, size, len);
949 }
950 virtual void need_on_actionbus(Table *att, TableOutputModifier mod, int lo, int hi, int size);
951 static bool allow_bus_sharing(Table *t1, Table *t2);
952 virtual Call &action_call() { return action; }
953 virtual Call &instruction_call() { return instruction; }
954 virtual Actions *get_actions() const { return actions.get(); }
955 virtual const std::vector<NextTables> &get_hit_next() const { return hit_next; }
956 virtual const NextTables &get_miss_next() const { return miss_next; }
957 virtual bool is_directly_referenced(const Table::Call &c) const;
958 virtual void add_reference_table(json::vector &table_refs, const Table::Call &c) const;
959 json::map &add_pack_format(json::map &stage_tbl, int memword, int words,
960 int entries = -1) const;
961 json::map &add_pack_format(json::map &stage_tbl, Table::Format *format, bool pad_zeros = true,
962 bool print_fields = true,
963 Table::Actions::Action *act = nullptr) const;
964 virtual void add_field_to_pack_format(json::vector &field_list, unsigned basebit,
965 std::string name, const Table::Format::Field &field,
966 const Table::Actions::Action *act) const;
967 virtual bool validate_call(Table::Call &call, MatchTable *self, size_t required_args,
968 int hash_dist_type, Table::Call &first_call) {
969 BUG("unsupported");
970 return false;
971 }
972 bool validate_instruction(Table::Call &call) const;
973 // const std::vector<Actions::Action::alias_value_t *> &);
974 // Generate the context json for a field into field list.
975 // Use the bits specified in field, offset by the base bit.
976 // If the field is a constant, output a const_tuple map, including the specified value.
977 void output_field_to_pack_format(json::vector &field_list, unsigned basebit, std::string name,
978 std::string source, unsigned start_bit,
979 const Table::Format::Field &field, unsigned value = 0) const;
980 void add_zero_padding_fields(Table::Format *format, Table::Actions::Action *act = nullptr,
981 unsigned format_width = 64) const;
982 void get_cjson_source(const std::string &field_name, std::string &source, int &start_bit) const;
983 // Result physical buses should be setup for
984 // Exact/Hash/MatchwithNoKey/ATCAM/Ternary tables
985 virtual void add_result_physical_buses(json::map &stage_tbl) const;
986 virtual void merge_context_json(json::map &tbl, json::map &stage_tbl) const;
987 void canon_field_list(json::vector &field_list) const;
988 void for_all_next(std::function<void(const Ref &)> fn);
989 void check_next(const Ref &next);
990 void check_next(NextTables &next);
991 void check_next();
992 virtual void set_pred();
993 /* find the predecessors in the given stage that must run iff this table runs.
994 * includes `this` if it is in the stage. The values are the set of actions that
995 * (lead to) triggering this table, or empty if any action might */
996 std::map<Table *, std::set<Actions::Action *>> find_pred_in_stage(
997 int stageno, const std::set<Actions::Action *> &acts = std::set<Actions::Action *>());
998
999 bool choose_logical_id(const slist<Table *> *work = nullptr);
1000 virtual int hit_next_size() const { return hit_next.size(); }
1001 virtual int get_tcam_id() const { BUG("%s not a TCAM table", name()); }
1002
1003 const std::vector<const p4_param *> find_p4_params(std::string s, std::string t = "",
1004 int start_bit = -1, int width = -1) const {
1005 remove_name_tail_range(s);
1006 std::vector<const p4_param *> params;
1007 if (start_bit <= -1) return params;
1008 if (width <= -1) return params;
1009 int end_bit = start_bit + width;
1010 for (auto &p : p4_params_list) {
1011 if ((p.name == s) || (p.alias == s)) {
1012 int p_end_bit = p.start_bit + p.bit_width;
1013 if (!t.empty() && (p.type != t)) continue;
1014 if (p.start_bit > static_cast<unsigned>(start_bit)) continue;
1015 if (p_end_bit < end_bit) continue;
1016 params.push_back(&p);
1017 }
1018 }
1019 return params;
1020 }
1021
1022 const p4_param *find_p4_param(std::string s, std::string t = "", int start_bit = -1,
1023 int width = -1) const {
1024 remove_name_tail_range(s);
1025 std::vector<p4_param *> params;
1026 for (auto &p : p4_params_list) {
1027 if ((p.name == s) || (p.alias == s)) {
1028 if (!t.empty() && (p.type != t)) continue;
1029 if ((start_bit > -1) && (static_cast<unsigned>(start_bit) < p.start_bit)) continue;
1030 if ((width > -1) && (p.start_bit + p.bit_width < start_bit + width)) continue;
1031 return &p;
1032 }
1033 }
1034 return nullptr;
1035 }
1036
1037 const p4_param *find_p4_param_type(std::string &s) const {
1038 for (auto &p : p4_params_list)
1039 if (p.type == s) return &p;
1040 return nullptr;
1041 }
1042 virtual std::string get_default_action() {
1043 return (!default_action.empty()) ? default_action : action ? action->default_action : "";
1044 }
1045 virtual default_action_params *get_default_action_parameters() {
1046 return (!default_action_parameters.empty()) ? &default_action_parameters
1047 : action ? &action->default_action_parameters
1048 : nullptr;
1049 }
1050 virtual unsigned get_default_action_handle() const {
1051 return default_action_handle > 0 ? default_action_handle
1052 : action ? action->default_action_handle
1053 : 0;
1054 }
1055 int get_format_field_size(std::string s) const {
1056 if (auto field = lookup_field(s)) return field->size;
1057 return 0;
1058 }
1059 virtual bool needs_handle() const { return false; }
1060 virtual bool needs_next() const { return false; }
1061 virtual bitvec compute_reachable_tables();
1062 bitvec reachable_tables() {
1063 if (!reachable_tables_) reachable_tables_ = compute_reachable_tables();
1064 return reachable_tables_;
1065 }
1066 std::string loc() const;
1067};
1068
1069std::ostream &operator<<(std::ostream &, const Table::Layout &);
1070std::ostream &operator<<(std::ostream &, const Table::Layout::bus_type_t);
1071
1072class FakeTable : public Table {
1073 public:
1074 explicit FakeTable(const char *name) : Table(-1, name, INGRESS, 0, -1) {}
1075 void setup(VECTOR(pair_t) & data) override { assert(0); }
1076 void pass1() override { assert(0); }
1077 void pass2() override { assert(0); }
1078 void pass3() override { assert(0); }
1079 FOR_ALL_REGISTER_SETS(TARGET_OVERLOAD, void write_regs, (mau_regs &), override { assert(0); })
1080 void gen_tbl_cfg(json::vector &out) const override { assert(0); }
1081};
1082
1083class AlwaysRunTable : public Table {
1084 /* a 'table' to hold the always run action in a stage */
1085 public:
1086 AlwaysRunTable(gress_t gress, Stage *stage, pair_t &init);
1087 void setup(VECTOR(pair_t) & data) override { assert(0); }
1088 void pass1() override { actions->pass1(this); }
1089 void pass2() override { actions->pass2(this); }
1090 void pass3() override {}
1091 FOR_ALL_REGISTER_SETS(TARGET_OVERLOAD, void write_regs, (mau_regs & regs), override)
1092 void gen_tbl_cfg(json::vector &out) const override {}
1093};
1094
1096 Table::Call selector;
1097 Table::Call selector_length;
1098 std::vector<Table::Call> stats, meters, statefuls;
1099 Table::Call meter_color;
1100 SelectionTable *get_selector() const;
1101 MeterTable *get_meter(std::string name = "") const;
1102 StatefulTable *get_stateful(std::string name = "") const;
1103 Table::Format::Field *find_address_field(const AttachedTable *tbl) const;
1104 const Table::Call *get_call(const Table *) const;
1105 bool is_attached(const Table *tbl) const { return get_call(tbl) != nullptr; }
1106 void pass0(MatchTable *self);
1107 void pass1(MatchTable *self);
1108 template <class REGS>
1109 void write_merge_regs(REGS &regs, MatchTable *self, int type, int bus);
1110 template <class REGS>
1111 void write_tcam_merge_regs(REGS &regs, MatchTable *self, int bus, int tcam_shift);
1112 bool run_at_eop();
1113 bitvec compute_reachable_tables() const;
1114};
1115
1116#define DECLARE_ABSTRACT_TABLE_TYPE(TYPE, PARENT, ...) \
1117 class TYPE : public PARENT { \
1118 protected: \
1119 TYPE(int l, const char *n, gress_t g, Stage *s, int lid) : PARENT(l, n, g, s, lid) {} \
1120 __VA_ARGS__ \
1121 };
1122
1123// clang-format off
1124DECLARE_ABSTRACT_TABLE_TYPE(
1125 MatchTable, Table, GatewayTable *gateway = 0; IdletimeTable *idletime = 0;
1126 AttachedTables attached; bool always_run = false; friend struct AttachedTables;
1127 enum {NONE = 0, TABLE_MISS = 1, TABLE_HIT = 2, DISABLED = 3, GATEWAY_MISS = 4, GATEWAY_HIT = 5,
1128 GATEWAY_INHIBIT = 6} table_counter = NONE;
1129
1130 using Table::pass1; using Table::write_regs;
1131 template <class TARGET> void write_common_regs(typename TARGET::mau_regs &, int, Table *);
1132 template <class REGS> void write_regs(REGS &, int type, Table *result);
1133 template <class REGS> void write_next_table_regs(REGS &, Table *);
1134 void common_init_setup(const VECTOR(pair_t) &, bool, P4Table::type) override;
1135 bool common_setup(pair_t &, const VECTOR(pair_t) &, P4Table::type) override;
1136 int get_address_mau_actiondata_adr_default(unsigned log2size, bool per_flow_enable); public
1137 : bool is_always_run() const override { return always_run; } void pass0() override;
1138 void pass1() override; void pass3() override; bool is_alpm() const {
1139 if (p4_table) {
1140 return p4_table->is_alpm();
1141 }
1142 return false;
1143 } bool is_attached(const Table *tbl) const override;
1144 const Table::Call *get_call(const Table *tbl) const {
1145 return get_attached()->get_call(tbl);
1146 } const AttachedTables *get_attached() const override { return &attached; } std::vector<Call>
1147 get_calls() const override;
1148 AttachedTables * get_attached() override { return &attached; } Format *
1149 get_format() const override;
1150 const GatewayTable *get_gateway()
1151 const override { return gateway; } const MatchTable *get_match_table() const override {
1152 return this;
1153 } MatchTable *get_match_table() override { return this; } std::set<MatchTable *>
1154 get_match_tables() override {
1155 std::set<MatchTable *> rv;
1156 rv.insert(this);
1157 return rv;
1158 } Format::Field *find_address_field(const AttachedTable *tbl) const override {
1159 return attached.find_address_field(tbl);
1160 } Format::Field *lookup_field(const std::string &n, const std::string &act = "")
1161 const override;
1162 bool run_at_eop() override { return attached.run_at_eop(); }
1163 virtual bool is_ternary() { return false; }
1164 void gen_idletime_tbl_cfg(json::map &stage_tbl) const;
1165 int direct_shiftcount() const override {
1166 return 64;
1167 } void gen_hash_bits(const std::map<int, HashCol> &hash_table, InputXbar::HashTable ht_id,
1168 json::vector &hash_bits, unsigned hash_group_no, bitvec hash_bits_used)
1169 const;
1170 virtual void add_hash_functions(json::map &stage_tbl) const;
1171 void add_all_reference_tables(json::map &tbl, Table *math_table = nullptr) const;
1172 METER_ACCESS_TYPE default_meter_access_type(bool for_stateful);
1173 bool needs_handle() const override { return true; }
1174 bool needs_next() const override { return true; }
1175 bitvec compute_reachable_tables() override;
1176)
1177// clang-format on
1178
1179#define DECLARE_TABLE_TYPE(TYPE, PARENT, NAME, ...) \
1180 class TYPE : public PARENT { /* NOLINT */ \
1181 static struct Type : public Table::Type { \
1182 Type() : Table::Type(NAME) {} \
1183 TYPE *create(int lineno, const char *name, gress_t gress, Stage *stage, int lid, \
1184 VECTOR(pair_t) & data); \
1185 } table_type_singleton; \
1186 friend struct Type; \
1187 \
1188 protected: \
1189 TYPE(int l, const char *n, gress_t g, Stage *s, int lid) : PARENT(l, n, g, s, lid) {} \
1190 void setup(VECTOR(pair_t) & data) override; \
1191 \
1192 public: \
1193 void pass1() override; \
1194 void pass2() override; \
1195 void pass3() override; \
1196 /* gcc gets confused by overloading this template with the virtual \
1197 * functions if we try to specialize the templates, so we mangle \
1198 * the name with a _vt extension to help it out. */ \
1199 template <class REGS> \
1200 void write_regs_vt(REGS &regs); \
1201 FOR_ALL_REGISTER_SETS(TARGET_OVERLOAD, void write_regs, (mau_regs & regs), override) \
1202 void gen_tbl_cfg(json::vector &out) const override; \
1203 \
1204 private: \
1205 __VA_ARGS__ \
1206 };
1207
1208#define DEFINE_TABLE_TYPE(TYPE) \
1209 TYPE::Type TYPE::table_type_singleton; \
1210 TYPE *TYPE::Type::create(int lineno, const char *name, gress_t gress, Stage *stage, int lid, \
1211 VECTOR(pair_t) & data) { \
1212 TYPE *rv = new TYPE(lineno, name, gress, stage, lid); \
1213 rv->setup(data); \
1214 return rv; \
1215 } \
1216 FOR_ALL_REGISTER_SETS(TARGET_OVERLOAD, void TYPE::write_regs, (mau_regs & regs), \
1217 { write_regs_vt(regs); })
1218
1219/* Used to create a subclass for a table type */
1220#define DEFINE_TABLE_TYPE_WITH_SPECIALIZATION(TYPE, KIND) \
1221 TYPE::Type TYPE::table_type_singleton; \
1222 TYPE *TYPE::Type::create(int lineno, const char *name, gress_t gress, Stage *stage, int lid, \
1223 VECTOR(pair_t) & data) { \
1224 SWITCH_FOREACH_##KIND(options.target, \
1225 auto *rv = new TARGET::TYPE(lineno, name, gress, stage, lid); \
1226 rv->setup(data); return rv;) \
1227 } \
1228 FOR_ALL_REGISTER_SETS(TARGET_OVERLOAD, void TYPE::write_regs, (mau_regs & regs), \
1229 { write_regs_vt(regs); })
1230
1231// clang-format off
1232DECLARE_ABSTRACT_TABLE_TYPE(SRamMatchTable, MatchTable, // exact, atcam, or proxy_hash
1233
1234 // NOLINTNEXTLINE (whitespace/indent)
1235 public:
1236 struct Ram : public MemUnit {
1237 using MemUnit::MemUnit;
1238 Ram(const MemUnit &m) : MemUnit(m) {}
1239 Ram(MemUnit &&m) : MemUnit(std::move(m)) {}
1240 bool isLamb() const { return stage == INT_MIN && row == -1; }
1241 const char *desc() const; // Short lived temp for messages
1242 };
1243 struct Way {
1244 int lineno;
1245 int group_xme; // hash group or xme
1246 int index; // first bit of index
1247 int index_hi = -1; // top bit (if set) for sanity checking
1248 int subword_bits;
1249 bitvec select;
1250 std::vector<Ram> rams;
1251 bool isLamb() const {
1252 BUG_CHECK(!rams.empty(), "no rams in way");
1253 return rams.at(0).isLamb(); }
1254 bitvec select_bits() const {
1255 bitvec rv = select;
1256 rv.setrange(index, (isLamb() ? LAMB_DEPTH_BITS : SRAM_DEPTH_BITS) + subword_bits);
1257 return rv;
1258 }
1259 };
1260
1261 // NOLINTNEXTLINE (whitespace/indent)
1262 protected:
1263 std::vector<Way> ways;
1264 struct WayRam { int way, index, word, bank; };
1265 std::map<Ram, WayRam> way_map;
1266 std::vector<MatchSource *> match;
1267 std::map<unsigned, MatchSource *> match_by_bit;
1268 std::vector<std::vector<MatchSource *>> match_in_word;
1269 std::vector<int> word_ixbar_group;
1270 struct GroupInfo {
1271 /* info about which word(s) are used per format group with wide matches */
1272 int overhead_word; /* which word of wide match contains overhead */
1273 int overhead_bit; /* lowest bit that contains overhead in that word */
1274 // The word that is going to contain the result bus. Same as the overhead word, if
1275 // the entry actually has overhead
1276 int result_bus_word;
1277 std::map<int, int> match_group; /* which match group for each word with match */
1278 std::vector<unsigned> tofino_mask; /* 14-bit tofino byte/nibble mask for each word */
1279 int vpn_offset; /* which vpn to use for this group */
1280 GroupInfo() : overhead_word(-1), overhead_bit(-1), result_bus_word(-1), vpn_offset(-1) {}
1281 // important function in order to determine shiftcount for exact match entries
1282 int result_bus_word_group() const { return match_group.at(result_bus_word); }
1283 }; // NOLINT
1284 std::vector<GroupInfo> group_info;
1285 std::vector<std::vector<int>> word_info; // which format group corresponds to each
1286 // match group in each word
1287 int mgm_lineno = -1; // match_group_map lineno
1288 friend class GatewayTable; // Gateway needs to examine word group details for compat
1289 friend class Target::Tofino::GatewayTable;
1290 bitvec version_nibble_mask;
1291 // Which hash groups are assigned to the hash_function_number in the hash_function json node
1292 // This is to coordinate with the hash_function_id in the ways
1293 std::map<unsigned, unsigned> hash_fn_ids;
1294
1295 // helper function only used/instantiated on tofino1/2
1296 template<class REGS>
1297 void write_attached_merge_regs(REGS &regs, int bus, int word, int word_group);
1298
1299 bool parse_ram(const value_t &, std::vector<Ram> &);
1300 bool parse_way(const value_t &);
1301 void common_sram_setup(pair_t &, const VECTOR(pair_t) &);
1302 void common_sram_checks();
1303 void alloc_global_busses() override;
1304 void alloc_vpns() override;
1305 int find_problematic_vpn_offset() const;
1306 virtual void setup_ways();
1307 void setup_hash_function_ids();
1308 void pass1() override;
1309 template<class REGS> void write_regs_vt(REGS &regs);
1310 FOR_ALL_REGISTER_SETS(TARGET_OVERLOAD,
1311 void write_regs, (mau_regs &regs), override )
1312 virtual std::string get_match_mode(const Phv::Ref &pref, int offset) const;
1313 json::map* add_common_sram_tbl_cfgs(json::map &tbl,
1314 std::string match_type, std::string stage_table_type) const;
1315 void add_action_cfgs(json::map &tbl, json::map &stage_tbl) const;
1316 virtual unsigned entry_ram_depth() const { return 1024; }
1317 unsigned get_number_entries() const;
1318 unsigned get_format_width() const;
1319 virtual int determine_pre_byteswizzle_loc(MatchSource *ms, int lo, int hi, int word);
1320 void add_field_to_pack_format(json::vector &field_list, unsigned basebit, std::string name,
1321 const Table::Format::Field &field,
1322 const Table::Actions::Action *act) const override;
1323 std::unique_ptr<json::map> gen_memory_resource_allocation_tbl_cfg_with_way(const Way &) const;
1324 Actions *get_actions() const override {
1325 return actions ? actions.get() : (action ? action->actions.get() : nullptr);
1326 }
1327 void add_hash_functions(json::map &stage_tbl) const override;
1328 virtual void gen_ghost_bits(int hash_function_number, json::vector &ghost_bits_to_hash_bits,
1329 json::vector &ghost_bits_info) const { }
1330 virtual void no_overhead_determine_result_bus_usage();
1331
1332 // NOLINTNEXTLINE (whitespace/indent)
1333 public:
1334 Format::Field *lookup_field(const std::string &n, const std::string &act = "") const override;
1335 OVERLOAD_FUNC_FOREACH(TARGET_CLASS, virtual void, setup_word_ixbar_group, (), ())
1336 OVERLOAD_FUNC_FOREACH(TARGET_CLASS, virtual void, verify_format, (), ())
1337 OVERLOAD_FUNC_FOREACH(TARGET_CLASS, virtual void, verify_format_pass2, (), ())
1338 virtual bool verify_match_key();
1339 void verify_match(unsigned fmt_width);
1340 void vpn_params(int &width, int &depth, int &period, const char *&period_name) const override {
1341 width = (format->size-1)/128 + 1;
1342 period = format->groups();
1343 depth = period * layout_size() / width;
1344 period_name = "match group size"; }
1345 template<class REGS> void write_merge_regs_vt(REGS &regs, int type, int bus) {
1346 attached.write_merge_regs(regs, this, type, bus); }
1347 FOR_ALL_REGISTER_SETS(TARGET_OVERLOAD,
1348 void write_merge_regs, (mau_regs &regs, int type, int bus), override {
1349 write_merge_regs_vt(regs, type, bus); })
1350 bool is_match_bit(const std::string name, const int bit) const {
1351 for (auto *m : match) {
1352 std::string m_name = m->name();
1353 int m_lo = remove_name_tail_range(m_name) + m->fieldlobit();
1354 int m_hi = m_lo + m->size() -1;
1355 if (m_name == name) {
1356 if (m_lo <= bit
1357 && m_hi >= bit)
1358 return true;
1359 }
1360 }
1361 return false;
1362 }
1363 void determine_word_and_result_bus() override;
1364 SelectionTable *get_selector() const override { return attached.get_selector(); }
1365 StatefulTable *get_stateful() const override { return attached.get_stateful(); }
1366 MeterTable* get_meter() const override { return attached.get_meter(); }
1367 const Way *way_for_ram(Ram r) const {
1368 return way_map.count(r) ? &ways[way_map.at(r).way] : nullptr; }
1369 const Way *way_for_xme(int xme) const {
1370 for (auto &way : ways) if (way.group_xme == xme) return &way;
1371 return nullptr; }
1372)
1373// clang-format on
1374
1375// clang-format off
1376DECLARE_TABLE_TYPE(
1377 ExactMatchTable, SRamMatchTable, "exact_match", bool dynamic_key_masks = false;
1378
1379 // The position of the ghost bits in a single hash function
1380 // The key is name of the field and the field bit, the value is one-hot for all
1381 // bits that this ghost bit has an impact on
1382 using GhostBitPositions = std::map<std::pair<std::string, int>, bitvec>;
1383 std::map<int, GhostBitPositions> ghost_bit_positions; std::unique_ptr<Format> stash_format;
1384 std::vector<int> stash_rows; std::vector<int> stash_cols; std::vector<int> stash_units;
1385 std::vector<int> stash_overhead_rows;
1386
1387 // NOLINTNEXTLINE (whitespace/indent)
1388 public
1389 : int unitram_type() override { return UnitRam::MATCH; } table_type_t table_type()
1390 const override { return EXACT; } bool has_group(int grp) {
1391 for (auto &way : ways)
1392 if (way.group_xme == grp) return true;
1393 return false;
1394 } void determine_ghost_bits();
1395 void gen_ghost_bits(int hash_function_number, json::vector &ghost_bits_to_hash_bits,
1396 json::vector &ghost_bits_info) const override;
1397 void generate_stash_overhead_rows();)
1398
1399DECLARE_TABLE_TYPE(
1400 AlgTcamMatchTable, SRamMatchTable, "atcam_match",
1401 // key is column priority, value is way index
1402 std::map<int, int> col_priority_way;
1403 int number_partitions = 0; int max_subtrees_per_partition = 0; int bins_per_partition = 0;
1404 int atcam_subset_width = 0; int shift_granularity = 0; std::string partition_field_name = "";
1405 std::vector<int> ixbar_subgroup, ixbar_mask; struct match_element {
1406 Phv::Ref *field;
1407 unsigned offset, width;
1408 };
1409 bitvec s0q1_nibbles, s1q0_nibbles; std::vector<Phv::Ref *> s0q1_prefs, s1q0_prefs;
1410 std::map<int, match_element> s0q1, s1q0; table_type_t table_type()
1411 const override { return ATCAM; };
1412 void verify_format(Target::Tofino) override;
1413 void verify_entry_priority(); void setup_column_priority(); void find_tcam_match();
1414 void gen_unit_cfg(json::vector &units, int size) const;
1415 std::unique_ptr<json::vector> gen_memory_resource_allocation_tbl_cfg_no_input() const;
1416 void setup_nibble_mask(Table::Format::Field *match, int group,
1417 std::map<int, match_element> &elems, bitvec &mask);
1418 std::string get_match_mode(const Phv::Ref &pref, int offset) const override;
1419 void base_alpm_atcam_tbl_cfg(json::map &atcam_tbl, const char *type, int size) const {
1420 if (p4_table) p4_table->base_alpm_tbl_cfg(atcam_tbl, size, this, P4Table::Atcam);
1421 }
1422 // For ATCAM tables, no hash functions are generated for the table, as the current
1423 // interpretation of the table is that the partition index is an identity hash function.
1424 // Potentially this could change at some point
1425 void add_hash_functions(json::map &stage_tbl)
1426 const override {} bool has_directly_attached_synth2port() const;
1427 std::string get_lpm_field_name() const {
1428 std::string lpm = "lpm";
1429 if (auto *p = find_p4_param_type(lpm))
1430 return p->key_name.empty() ? p->name : p->key_name;
1431 else
1432 error(lineno, "'lpm' type field not found in alpm atcam '%s-%s' p4 param order", name(),
1433 p4_name());
1434 return "";
1435 } std::set<unsigned>
1436 get_partition_action_handle() const {
1437 if (p4_table) return p4_table->get_partition_action_handle();
1438 return {};
1439 } void no_overhead_determine_result_bus_usage() override;
1440 std::string get_partition_field_name() const {
1441 if (!p4_table) return "";
1442 auto name = p4_table->get_partition_field_name();
1443 if (auto *p = find_p4_param(name))
1444 if (!p->key_name.empty()) return p->key_name;
1445 return name;
1446 } unsigned entry_ram_depth() const override {
1447 return std::min(number_partitions, 1024);
1448 } void gen_alpm_cfg(json::map &) const;
1449)
1450// clang-format on
1451
1452// clang-format off
1453DECLARE_TABLE_TYPE(
1454 ProxyHashMatchTable, SRamMatchTable, "proxy_hash", bool dynamic_key_masks = false;
1455 void setup_ways() override; int proxy_hash_group = -1; std::string proxy_hash_alg = "<invalid>";
1456 bool verify_match_key() override; table_type_t table_type()
1457 const override { return PROXY_HASH; } void setup_word_ixbar_group() override;
1458 int determine_pre_byteswizzle_loc(MatchSource *ms, int lo, int hi, int word) override;
1459 void add_proxy_hash_function(json::map &stage_tbl) const;
1460)
1461// clang-format on
1462
1463DECLARE_TABLE_TYPE(TernaryMatchTable, MatchTable, "ternary_match",
1464
1465 // NOLINTNEXTLINE (whitespace/indent)
1466 protected:
1467 void vpn_params(int &width, int &depth, int &period, const char *&period_name) const override;
1468 struct Match {
1469 int lineno = -1, word_group = -1, byte_group = -1, byte_config = 0, dirtcam = 0;
1470 Match() {}
1471 explicit Match(const value_t &);
1472 };
1473 enum range_match_t { TCAM_NORMAL = 0, DIRTCAM_2B = 1, DIRTCAM_4B_LO = 2,
1474 DIRTCAM_4B_HI = 3, NONE = 4 };
1475 enum byte_config_t { MIDBYTE_NIBBLE_LO = 0, MIDBYTE_NIBBLE_HI = 1 };
1476 std::vector<Match> match;
1477 int match_word(int word_group) const {
1478 for (unsigned i = 0; i < match.size(); i++)
1479 if (match[i].word_group == word_group)
1480 return i;
1481 return -1; }
1482 unsigned chain_rows[TCAM_UNITS_PER_ROW]; /* bitvector per column */
1483 enum { ALWAYS_ENABLE_ROW = (1<<2) | (1<<5) | (1<<9) };
1484 friend class TernaryIndirectTable;
1485
1486 virtual void check_tcam_match_bus(const std::vector<Table::Layout> &) = 0;
1487
1488 // NOLINTNEXTLINE (whitespace/indent)
1489 public:
1490 void pass0() override;
1491 int tcam_id = -1;
1492 Table::Ref indirect;
1493 int indirect_bus = -1; /* indirect bus to use if there's no indirect table */
1494 void alloc_vpns() override;
1495 range_match_t get_dirtcam_mode(int group, int byte) const {
1496 BUG_CHECK(group >= 0, "group must be >= 0");
1497 BUG_CHECK(byte >= 0, "byte must be >= 0");
1498 range_match_t dirtcam_mode = NONE;
1499 for (auto &m : match) {
1500 if (m.word_group == group) {
1501 dirtcam_mode = (range_match_t) ((m.dirtcam >> 2*byte) & 0x3); } }
1502 return dirtcam_mode; }
1503 Format::Field *lookup_field(const std::string &name, const std::string &action) const override;
1504 HashDistribution *find_hash_dist(int unit) override {
1505 return indirect ? indirect->find_hash_dist(unit) : Table::find_hash_dist(unit); }
1506 int find_on_actionbus(const ActionBusSource &src, int lo, int hi, int size,
1507 int pos = -1) override {
1508 return indirect ? indirect->find_on_actionbus(src, lo, hi, size, pos)
1509 : Table::find_on_actionbus(src, lo, hi, size, pos); }
1510 void need_on_actionbus(const ActionBusSource &src, int lo, int hi, int size) override {
1511 indirect ? indirect->need_on_actionbus(src, lo, hi, size)
1512 : Table::need_on_actionbus(src, lo, hi, size); }
1513 int find_on_actionbus(const char *n, TableOutputModifier mod, int lo, int hi,
1514 int size, int *len = 0) override {
1515 return indirect ? indirect->find_on_actionbus(n, mod, lo, hi, size, len)
1516 : Table::find_on_actionbus(n, mod, lo, hi, size, len); }
1517 void need_on_actionbus(Table *att, TableOutputModifier mod, int lo, int hi, int size) override {
1518 indirect ? indirect->need_on_actionbus(att, mod, lo, hi, size)
1519 : Table::need_on_actionbus(att, mod, lo, hi, size); }
1520 const Call &get_action() const override { return indirect ? indirect->get_action() : action; }
1521 Actions *get_actions() const override { return actions ? actions.get() :
1522 (action ? action->actions.get() : indirect ? indirect->actions ? indirect->actions.get() :
1523 indirect->action ? indirect->action->actions.get() : 0 : 0); }
1524 const AttachedTables *get_attached() const override {
1525 return indirect ? indirect->get_attached() : &attached; }
1526 AttachedTables *get_attached() override {
1527 return indirect ? indirect->get_attached() : &attached; }
1528 SelectionTable *get_selector() const override {
1529 return indirect ? indirect->get_selector() : 0; }
1530 StatefulTable *get_stateful() const override {
1531 return indirect ? indirect->get_stateful() : 0; }
1532 MeterTable* get_meter() const override {
1533 return indirect ? indirect->get_meter() : 0; }
1534 bool is_attached(const Table *tbl) const override {
1535 return indirect ? indirect->is_attached(tbl) : MatchTable::is_attached(tbl); }
1536 Format::Field *find_address_field(const AttachedTable *tbl) const override {
1537 return indirect ? indirect->find_address_field(tbl) : attached.find_address_field(tbl); }
1538 std::unique_ptr<json::map> gen_memory_resource_allocation_tbl_cfg(
1539 const char *type, const std::vector<Layout> &layout,
1540 bool skip_spare_bank = false) const override;
1541 json::map &get_tbl_top(json::vector &out) const;
1542 Call &action_call() override { return indirect ? indirect->action : action; }
1543 Call &instruction_call() override { return indirect ? indirect->instruction: instruction; }
1544 int json_memunit(const MemUnit &u) const override {
1545 return u.row + u.col*12; }
1546 bool is_ternary() override { return true; }
1547 bool has_indirect() { return indirect; }
1548 int hit_next_size() const override {
1549 if (indirect && indirect->hit_next.size() > 0)
1550 return indirect->hit_next.size();
1551 return hit_next.size(); }
1552 table_type_t table_type() const override { return TERNARY; }
1553 void gen_entry_cfg(json::vector &out, std::string name,
1554 unsigned lsb_offset, unsigned lsb_idx, unsigned msb_idx,
1555 std::string source, unsigned start_bit, unsigned field_width,
1556 unsigned index, bitvec &tcam_bits, unsigned byte_offset) const;
1557 void gen_entry_cfg2(json::vector &out, std::string field_name, std::string global_name,
1558 unsigned lsb_offset, unsigned lsb_idx, unsigned msb_idx, std::string source,
1559 unsigned start_bit, unsigned field_width, bitvec &tcam_bits) const;
1560 void gen_entry_range_cfg(json::map &entry, bool duplicate, unsigned nibble_offset) const;
1561 void set_partition_action_handle(unsigned handle) {
1562 if (p4_table) p4_table->set_partition_action_handle(handle); }
1563 void set_partition_field_name(std::string name) {
1564 if (p4_table) p4_table->set_partition_field_name(name); }
1565 void base_alpm_pre_classifier_tbl_cfg(json::map &pre_classifier_tbl,
1566 const char *type, int size) const {
1567 if (p4_table)
1568 p4_table->base_alpm_tbl_cfg(pre_classifier_tbl, size, this, P4Table::PreClassifier);
1569 }
1570 virtual void gen_match_fields_pvp(json::vector &match_field_list, unsigned word,
1571 bool uses_versioning, unsigned version_word_group, bitvec &tcam_bits) const;
1572 virtual void gen_match_fields(json::vector &match_field_list,
1573 std::vector<bitvec> &tcam_bits) const;
1574 unsigned get_default_action_handle() const override {
1575 unsigned def_act_handle = Table::get_default_action_handle();
1576 return def_act_handle > 0 ? def_act_handle :
1577 indirect ? indirect->get_default_action_handle() ?
1578 indirect->get_default_action_handle() : action ?
1579 action->default_action_handle : 0 : 0;
1580 }
1581 std::string get_default_action() override {
1582 std::string def_act = Table::get_default_action();
1583 return !def_act.empty() ? def_act : indirect ? indirect->default_action : ""; }
1584 Format* get_format() const override {
1585 return indirect ? indirect->get_format() : MatchTable::get_format(); }
1586 template<class REGS> void write_merge_regs_vt(REGS &regs, int type, int bus) {
1587 attached.write_merge_regs(regs, this, type, bus); }
1588 FOR_ALL_REGISTER_SETS(TARGET_OVERLOAD,
1589 void write_merge_regs, (mau_regs &regs, int type, int bus), override {
1590 write_merge_regs_vt(regs, type, bus); })
1591 void add_result_physical_buses(json::map &stage_tbl) const override;
1592 default_action_params* get_default_action_parameters() override {
1593 if (!default_action_parameters.empty()) return &default_action_parameters;
1594 auto def_action_params = indirect ? indirect->get_default_action_parameters() : nullptr;
1595 return def_action_params; }
1596 bitvec compute_reachable_tables() override;
1597 int get_tcam_id() const override { return tcam_id; }
1598 virtual void setup_indirect(const value_t &v) {
1599 if (CHECKTYPE(v, tSTR))
1600 indirect = v; }
1601
1602 // NOLINTNEXTLINE (whitespace/indent)
1603 private:
1604 template<class REGS> void tcam_table_map(REGS &regs, int row, int col);
1605)
1606
1607DECLARE_TABLE_TYPE(
1608 Phase0MatchTable, MatchTable, "phase0_match", int size = MAX_PORTS; int width = 1;
1609 int constant_value = 0; table_type_t table_type() const override { return PHASE0; }
1610 // Phase0 Tables are not actual tables. They cannot have action data
1611 // or attached tables and do not need a logical id assignment, hence
1612 // we skip pass0
1613 void pass0() override {} void set_pred() override { return; } bool needs_next() const override {
1614 return false;
1615 } int ram_word_width() const override { return Target::PHASE0_FORMAT_WIDTH(); })
1616DECLARE_TABLE_TYPE(
1617 HashActionTable, MatchTable, "hash_action", public
1618 :
1619 // int row = -1, bus = -1;
1620 table_type_t table_type() const override { return HASH_ACTION; } template <class REGS>
1621 void write_merge_regs_vt(REGS &regs, int type, int bus);
1622 FOR_ALL_REGISTER_SETS(TARGET_OVERLOAD, void write_merge_regs,
1623 (mau_regs & regs, int type, int bus), override) Format::Field *
1624 lookup_field(const std::string &n, const std::string &act = "") const override;
1625 void add_hash_functions(json::map &stage_tbl) const override;
1626 void determine_word_and_result_bus() override;
1627 Layout::bus_type_t default_bus_type() const override { return Layout::RESULT_BUS; })
1628
1629DECLARE_TABLE_TYPE(TernaryIndirectTable, Table, "ternary_indirect",
1630
1631 // NOLINTNEXTLINE (whitespace/indent)
1632 protected:
1633 TernaryMatchTable *match_table = nullptr;
1634 AttachedTables attached;
1635 table_type_t table_type() const override { return TERNARY_INDIRECT; }
1636 table_type_t set_match_table(MatchTable *m, bool indirect) override;
1637 void vpn_params(int &width, int &depth, int &period, const char *&period_name) const override {
1638 width = (format->size-1)/128 + 1;
1639 depth = layout_size() / width;
1640 period = 1;
1641 period_name = 0; }
1642 Actions *get_actions() const override {
1643 return actions ? actions.get() : (match_table ? match_table->actions.get() : nullptr);
1644 }
1645 const AttachedTables *get_attached() const override { return &attached; }
1646 AttachedTables *get_attached() override { return &attached; }
1647 const GatewayTable *get_gateway() const override { return match_table->get_gateway(); }
1648 const MatchTable *get_match_table() const override { return match_table; }
1649 std::set<MatchTable *> get_match_tables() override {
1650 std::set<MatchTable *> rv;
1651 if (match_table) rv.insert(match_table);
1652 return rv; }
1653 SelectionTable *get_selector() const override { return attached.get_selector(); }
1654 StatefulTable *get_stateful() const override { return attached.get_stateful(); }
1655 MeterTable* get_meter() const override { return attached.get_meter(); }
1656 bool is_attached(const Table *tbl) const override { return attached.is_attached(tbl); }
1657 Format::Field *find_address_field(const AttachedTable *tbl) const override {
1658 return attached.find_address_field(tbl); }
1659 template<class REGS> void write_merge_regs_vt(REGS &regs, int type, int bus) {
1660 attached.write_merge_regs(regs, match_table, type, bus); }
1661 FOR_ALL_REGISTER_SETS(TARGET_OVERLOAD,
1662 void write_merge_regs, (mau_regs &regs, int type, int bus), override {
1663 write_merge_regs_vt(regs, type, bus); })
1664 int unitram_type() override { return UnitRam::TERNARY_INDIRECTION; }
1665
1666 // NOLINTNEXTLINE (whitespace/indent)
1667 public:
1668 Format::Field *lookup_field(const std::string &n,
1669 const std::string &act = "") const override;
1670 MatchTable *get_match_table() override { return match_table; }
1671 const std::vector<NextTables> &get_hit_next() const override {
1672 if (hit_next.empty() && match_table)
1673 return match_table->get_hit_next();
1674 return Table::get_hit_next(); }
1675 const NextTables &get_miss_next() const override {
1676 if (!miss_next.set() && match_table)
1677 return match_table->get_miss_next();
1678 return Table::get_miss_next(); }
1679 int address_shift() const override { return std::min(5U, format->log2size - 2); }
1680 unsigned get_default_action_handle() const override {
1681 unsigned def_act_handle = Table::get_default_action_handle();
1682 return def_act_handle ? def_act_handle : action ? action->default_action_handle : 0; }
1683 bool needs_handle() const override { return true; }
1684 bool needs_next() const override { return true; }
1685 void determine_word_and_result_bus() override;
1686 bitvec compute_reachable_tables() override;
1687 int get_tcam_id() const override { return match_table->tcam_id; }
1688 Layout::bus_type_t default_bus_type() const override { return Layout::TIND_BUS; }
1689)
1690
1691// clang-format off
1692DECLARE_ABSTRACT_TABLE_TYPE(
1693 AttachedTable, Table,
1694 /* table that can be attached to multiple match tables to do something */
1695 std::set<MatchTable *> match_tables;
1696 bool direct = false, indirect = false; bool per_flow_enable = false;
1697 std::string per_flow_enable_param = "";
1698 virtual unsigned per_flow_enable_bit(MatchTable *m = nullptr) const;
1699 table_type_t set_match_table(MatchTable * m, bool indirect) override {
1700 if ((indirect && direct) || (!indirect && this->indirect))
1701 error(lineno, "Table %s is accessed with direct and indirect indices", name());
1702 this->indirect = indirect;
1703 direct = !indirect;
1704 match_tables.insert(m);
1705 if ((unsigned)m->logical_id < (unsigned)logical_id) logical_id = m->logical_id;
1706 return table_type();
1707 } const GatewayTable *get_gateway() const override {
1708 return match_tables.size() == 1 ? (*match_tables.begin())->get_gateway() : 0;
1709 } SelectionTable *get_selector() const override;
1710 StatefulTable * get_stateful() const override; MeterTable * get_meter() const override;
1711 Call &
1712 action_call() override {
1713 return match_tables.size() == 1 ? (*match_tables.begin())->action_call() : action;
1714 }
1715 int json_memunit(const MemUnit &u) const override;
1716 void pass1() override;
1717 virtual unsigned get_alu_index() const {
1718 if (layout.size() > 0) return layout[0].row / 4U;
1719 error(lineno, "Cannot determine ALU Index for table %s", name());
1720 return 0;
1721 } unsigned determine_meter_shiftcount(Table::Call &call, int group, int word, int tcam_shift)
1722 const;
1723 void determine_meter_merge_regs(MatchTable *match, int type, int bus,
1724 const std::vector<Call::Arg> &arg,
1725 METER_ACCESS_TYPE default_type, unsigned &adr_mask,
1726 unsigned &per_entry_mux_ctl, unsigned &adr_default,
1727 unsigned &meter_type_position);
1728
1729 // NOLINTNEXTLINE (whitespace/indent)
1730 protected
1731 :
1732 // Accessed by Meter/Selection/Stateful Tables as "meter_alu_index"
1733 // Accessed by Statistics (Counter) Tables as "stats_alu_index"
1734 void add_alu_index(json::map &stage_tbl, std::string alu_index) const;
1735
1736 // NOLINTNEXTLINE (whitespace/indent)
1737 public
1738 :
1739 const MatchTable *get_match_table()
1740 const override { return match_tables.size() == 1 ? *match_tables.begin() : 0; }
1741 MatchTable *get_match_table()
1742 override { return match_tables.size() == 1 ? *match_tables.begin() : 0; }
1743 std::set<MatchTable *>
1744 get_match_tables() override { return match_tables; } bool has_per_flow_enable()
1745 const { return per_flow_enable; } std::string get_per_flow_enable_param() {
1746 return per_flow_enable_param;
1747 } Format::Field *get_per_flow_enable_param(MatchTable *m) const override {
1748 return per_flow_enable ? m->lookup_field(per_flow_enable_param) : nullptr;
1749 } Format::Field *get_meter_address_param(MatchTable *m) const override {
1750 std::string pfe_name =
1751 per_flow_enable_param.substr(0, per_flow_enable_param.find("_pfe"));
1752 return per_flow_enable ? m->lookup_field(pfe_name + "_addr") : nullptr;
1753 } Format::Field *get_meter_type_param(MatchTable *m) const override {
1754 std::string pfe_name =
1755 per_flow_enable_param.substr(0, per_flow_enable_param.find("_pfe"));
1756 return per_flow_enable ? m->lookup_field(pfe_name + "_type") : nullptr;
1757 }
1758 bool get_per_flow_enable() { return per_flow_enable; } bool is_direct() const { return direct; }
1759 virtual int default_pfe_adjust() const { return 0; }
1760 std::string get_default_action() override {
1761 if (!default_action.empty()) return default_action;
1762 for (auto m : match_tables) {
1763 std::string def_action = m->get_default_action();
1764 if (!def_action.empty()) return def_action;
1765 }
1766 return "";
1767 }
1768 default_action_params *get_default_action_parameters() override {
1769 if (!default_action_parameters.empty()) return &default_action_parameters;
1770 for (auto m : match_tables) {
1771 if (auto def_action_params = m->get_default_action_parameters())
1772 if (!def_action_params->empty()) return def_action_params;
1773 }
1774 return nullptr;
1775 } bool validate_call(Table::Call &call, MatchTable *self, size_t required_args,
1776 int hash_dist_type, Table::Call &first_call) override;
1777 // used by Selection and Stateful tables.
1778 FOR_ALL_REGISTER_SETS(TARGET_OVERLOAD, int meter_alu_fifo_enable_from_mask,
1779 (mau_regs &, unsigned bytemask))
1780)
1781// clang-format on
1782
1783// clang-format off
1784DECLARE_TABLE_TYPE(
1785 ActionTable, AttachedTable, "action", protected
1786 : int action_id = -1;
1787 std::map<int, bitvec> home_rows_per_word; int home_lineno = -1;
1788 std::map<std::string, std::unique_ptr<Format>> action_formats;
1789 std::map<std::string, Actions::Action *> pack_actions;
1790 static const std::map<unsigned, std::vector<std::string>> action_data_address_huffman_encoding;
1791 void vpn_params(int &width, int &depth, int &period, const char *&period_name) const override;
1792 int get_start_vpn() override; std::string find_field(Format::Field * field) override;
1793 int find_field_lineno(Format::Field *field) override;
1794 Format::Field * lookup_field(const std::string &name, const std::string &action) const override;
1795 void apply_to_field(const std::string &n, std::function<void(Format::Field *)> fn) override;
1796 int find_on_actionbus(const char *n, TableOutputModifier mod, int lo, int hi, int size,
1797 int *len) override;
1798 int find_on_actionbus(const ActionBusSource &src, int lo, int hi, int size, int pos = -1)
1799 override;
1800 void need_on_actionbus(const ActionBusSource &src, int lo, int hi, int size) override;
1801 void need_on_actionbus(Table *att, TableOutputModifier mod, int lo, int hi, int size) override;
1802 table_type_t table_type() const override { return ACTION; } int unitram_type()
1803 override { return UnitRam::ACTION; } void pad_format_fields();
1804 unsigned get_do_care_count(std::string bstring);
1805 unsigned get_lower_huffman_encoding_bits(unsigned width); public
1806 : const std::map<std::string, std::unique_ptr<Format>> &get_action_formats()
1807 const { return action_formats; } unsigned get_size() const {
1808 unsigned size = 0;
1809 if (format) size = format->size;
1810 for (auto &f : get_action_formats()) {
1811 unsigned fsize = f.second->size;
1812 if (fsize > size) size = fsize;
1813 }
1814 return size;
1815 } unsigned get_log2size() const {
1816 unsigned size = get_size();
1817 return ceil_log2(size);
1818 } unsigned determine_shiftcount(Table::Call &call, int group, unsigned word, int tcam_shift)
1819 const override;
1820 unsigned determine_default(Table::Call &call) const;
1821 unsigned determine_mask(Table::Call &call) const;
1822 unsigned determine_vpn_shiftcount(Table::Call &call) const; bool needs_handle()
1823 const override { return true; } bool needs_next() const override { return true; }
1824)
1825// clang-format on
1826
1827// clang-format off
1828DECLARE_TABLE_TYPE(GatewayTable, Table, "gateway",
1829
1830 // NOLINTNEXTLINE (whitespace/indent)
1831 protected:
1832 MatchTable *match_table = 0;
1833 uint64_t payload = -1;
1834 int have_payload = -1;
1835 std::vector<int> payload_map;
1836 int match_address = -1;
1837 int gw_unit = -1;
1838 int payload_unit = -1;
1839 enum range_match_t { NONE, DC_2BIT, DC_4BIT }
1840 range_match = NONE;
1841 std::string gateway_name;
1842 std::string gateway_cond;
1843 bool always_run = false; // only for standalone
1844
1845 // NOLINTNEXTLINE (whitespace/indent)
1846 public:
1847 struct MatchKey {
1848 int offset;
1849 Phv::Ref val;
1850 bool valid; /* implicit valid bit for tofino1 only */
1851 MatchKey(gress_t gr, int stg, value_t &v) :
1852 offset(-1), val(gr, stg, v), valid(false) {}
1853 MatchKey(int off, gress_t gr, int stg, value_t &v) :
1854 offset(off), val(gr, stg, v), valid(false) {}
1855 // tofino1 only: phv has an implicit valid bit that can be matched in
1856 // gateway or ternary table.
1857 MatchKey(int off, gress_t gr, int stg, value_t &v, bool vld) :
1858 offset(off), val(gr, stg, v), valid(vld) {}
1859 bool operator<(const MatchKey &a) const { return offset < a.offset; }
1860 };
1861
1862 // NOLINTNEXTLINE (whitespace/indent)
1863 protected:
1864 std::vector<MatchKey> match, xor_match;
1865 struct Match {
1866 int lineno = 0;
1867 uint16_t range[6] = { 0, 0, 0, 0, 0, 0 };
1868 wmatch_t val;
1869 bool run_table = false;
1870 NextTables next;
1871 std::string action; // FIXME -- need arguments?
1872 int next_map_lut = -1;
1873 Match() {}
1874 Match(value_t *v, value_t &data, range_match_t range_match);
1875 } miss, cond_true, cond_false;
1876 std::vector<Match> table;
1877 bool need_next_map_lut = false;
1878 template<class REGS> void payload_write_regs(REGS &, int row, int type, int bus);
1879 template<class REGS> void standalone_write_regs(REGS &regs);
1880 FOR_ALL_REGISTER_SETS(TARGET_OVERLOAD,
1881 virtual void write_next_table_regs, (mau_regs &), { BUG("unsupported"); })
1882 bool gateway_needs_ixbar_group() {
1883 for (auto& m : match)
1884 if (m.offset < 32)
1885 return true;
1886 return !xor_match.empty(); }
1887
1888 // NOLINTNEXTLINE (whitespace/indent)
1889 public:
1890 table_type_t table_type() const override { return GATEWAY; }
1891 virtual int find_next_lut_entry(Table *tbl, const Match &match);
1892 const MatchTable *get_match_table() const override { return match_table; }
1893 MatchTable *get_match_table() override { return match_table; }
1894 std::set<MatchTable *> get_match_tables() override {
1895 std::set<MatchTable *> rv;
1896 if (match_table) rv.insert(match_table);
1897 return rv; }
1898 table_type_t set_match_table(MatchTable *m, bool indirect) override {
1899 match_table = m;
1900 if ((unsigned)m->logical_id < (unsigned)logical_id) logical_id = m->logical_id;
1901 return GATEWAY; }
1902 virtual void setup_map_indexing(Table *tbl) { return; }
1903 static GatewayTable *create(int lineno, const std::string &name, gress_t gress,
1904 Stage *stage, int lid, VECTOR(pair_t) &data)
1905 { return table_type_singleton.create(lineno, name.c_str(), gress, stage, lid, data); }
1906 const GatewayTable *get_gateway() const override { return this; }
1907 AttachedTables *get_attached() const override {
1908 return match_table ? match_table->get_attached() : 0; }
1909 SelectionTable *get_selector() const override {
1910 return match_table ? match_table->get_selector() : 0; }
1911 StatefulTable *get_stateful() const override {
1912 return match_table ? match_table->get_stateful() : 0; }
1913 MeterTable *get_meter() const override {
1914 return match_table ? match_table->get_meter() : 0; }
1915 bool empty_match() const { return match.empty() && xor_match.empty(); }
1916 unsigned input_use() const;
1917 bool needs_handle() const override { return true; }
1918 bool needs_next() const override { return true; }
1919 bool is_branch() const; // Tofino2 needs is_a_brnch set to use next_table
1920 void verify_format();
1921 bool is_always_run() const override { return always_run; }
1922 virtual bool check_match_key(MatchKey &, const std::vector<MatchKey> &, bool);
1923 virtual int gw_memory_unit() const = 0;
1924)
1925// clang-format on
1926
1927// clang-format off
1928DECLARE_TABLE_TYPE(
1929 SelectionTable, AttachedTable, "selection",
1930 bool non_linear_hash = false, /* == enable_sps_scrambling */
1931 resilient_hash = false; /* false is fair hash */
1932 int mode_lineno = -1, param = -1; std::vector<int> pool_sizes;
1933 int min_words = -1, max_words = -1; int selection_hash = -1; public
1934 : StatefulTable *bound_stateful = nullptr;
1935 table_type_t table_type()
1936 const override { return SELECTION; } void vpn_params(int &width, int &depth, int &period,
1937 const char *&period_name)
1938 const override {
1939 width = period = 1;
1940 depth = layout_size();
1941 period_name = 0;
1942 }
1943
1944 template <class REGS>
1945 void write_merge_regs_vt(REGS &regs, MatchTable *match, int type, int bus,
1946 const std::vector<Call::Arg> &args);
1947 template <class REGS> void setup_logical_alu_map(REGS &regs, int logical_id, int alu);
1948 template <class REGS> void setup_physical_alu_map(REGS &regs, int type, int bus, int alu);
1949 FOR_ALL_REGISTER_SETS(TARGET_OVERLOAD, void write_merge_regs,
1950 (mau_regs & regs, MatchTable *match, int type, int bus,
1951 const std::vector<Call::Arg> &args),
1952 override) int address_shift()
1953 const override { return 7; }
1954 std::vector<int> determine_spare_bank_memory_units() const override;
1955 unsigned meter_group() const { return layout.at(0).row / 4U; } int home_row() const override {
1956 return layout.at(0).row | 3;
1957 } int unitram_type() override { return UnitRam::SELECTOR; } StatefulTable *get_stateful()
1958 const override {
1959 return bound_stateful;
1960 } unsigned determine_shiftcount(Table::Call &call, int group, unsigned word, int tcam_shift)
1961 const override;
1962 void set_stateful(StatefulTable *s) override {
1963 bound_stateful = s;
1964 } unsigned per_flow_enable_bit(MatchTable *m = nullptr) const override;
1965 int indirect_shiftcount() const override;
1966 unsigned determine_length_shiftcount(const Table::Call &call, int group, int word) const;
1967 unsigned determine_length_mask(const Table::Call &call) const;
1968 unsigned determine_length_default(const Table::Call &call) const;
1969 bool validate_length_call(const Table::Call &call);)
1970
1971class IdletimeTable : public Table {
1972 MatchTable *match_table = 0;
1973 int sweep_interval = 7, precision = 3;
1974 bool disable_notification = false;
1975 bool two_way_notification = false;
1976 bool per_flow_enable = false;
1977
1978 IdletimeTable(int lineno, const char *name, gress_t gress, Stage *stage, int lid)
1979 : Table(lineno, name, gress, stage, lid) {}
1980 void setup(VECTOR(pair_t) & data) override;
1981
1982 public:
1983 table_type_t table_type() const override { return IDLETIME; }
1984 table_type_t set_match_table(MatchTable *m, bool indirect) override {
1985 match_table = m;
1986 if ((unsigned)m->logical_id < (unsigned)logical_id) logical_id = m->logical_id;
1987 return IDLETIME;
1988 }
1989 void vpn_params(int &width, int &depth, int &period, const char *&period_name) const override {
1990 width = period = 1;
1991 depth = layout_size();
1992 period_name = 0;
1993 }
1994 int json_memunit(const MemUnit &u) const override;
1995 int precision_shift() const;
1996 int direct_shiftcount() const override;
1997 void pass1() override;
1998 void pass2() override;
1999 void pass3() override;
2000 template <class REGS>
2001 void write_merge_regs_vt(REGS &regs, int type, int bus);
2002 template <class REGS>
2003 void write_regs_vt(REGS &regs);
2004 FOR_ALL_REGISTER_SETS(TARGET_OVERLOAD, void write_regs, (mau_regs & regs), override)
2005 FOR_ALL_REGISTER_SETS(TARGET_OVERLOAD, void write_merge_regs,
2006 (mau_regs & regs, int type, int bus), override)
2007 void gen_tbl_cfg(json::vector &out) const override { /* nothing at top level */ }
2008 void gen_stage_tbl_cfg(json::map &out) const;
2009 static IdletimeTable *create(int lineno, const std::string &name, gress_t gress, Stage *stage,
2010 int lid, VECTOR(pair_t) & data) {
2011 IdletimeTable *rv = new IdletimeTable(lineno, name.c_str(), gress, stage, lid);
2012 rv->setup(data);
2013 return rv;
2014 }
2015 bool needs_handle() const override { return true; }
2016 bool needs_next() const override { return true; }
2017 Layout::bus_type_t default_bus_type() const override { return Layout::IDLE_BUS; }
2018};
2019// clang-format on
2020
2021// clang-format off
2022DECLARE_ABSTRACT_TABLE_TYPE(
2023 Synth2Port, AttachedTable,
2024 void vpn_params(int &width, int &depth, int &period, const char *&period_name) const override {
2025 width = period = 1;
2026 depth = layout_size();
2027 period_name = 0;
2028 } bool global_binding = false;
2029 bool output_used = false; int home_lineno = -1; std::set<int, std::greater<int>> home_rows;
2030 json::map * add_stage_tbl_cfg(json::map & tbl, const char *type, int size) const override;
2031 public:
2032 int get_home_row_for_row(int row) const;
2033 void add_alu_indexes(json::map &stage_tbl, std::string alu_indexes) const;
2034 OVERLOAD_FUNC_FOREACH(TARGET_CLASS, std::vector<int>, determine_spare_bank_memory_units,
2035 () const, (), override)
2036 OVERLOAD_FUNC_FOREACH(TARGET_CLASS, void, alloc_vpns, (), (), override)
2037 template <class REGS> void write_regs_vt(REGS &regs);
2038 FOR_ALL_REGISTER_SETS(TARGET_OVERLOAD, void write_regs, (mau_regs & regs), override)
2039 FOR_ALL_REGISTER_SETS(TARGET_OVERLOAD, void write_merge_regs,
2040 (mau_regs & regs, MatchTable *match, int type, int bus,
2041 const std::vector<Call::Arg> &args),
2042 override = 0)
2043 void common_init_setup(const VECTOR(pair_t) &, bool, P4Table::type) override;
2044 bool common_setup(pair_t &, const VECTOR(pair_t) &, P4Table::type) override;
2045 void pass1() override; void pass2() override; void pass3() override;
2046)
2047
2048DECLARE_TABLE_TYPE(
2049 CounterTable, Synth2Port, "counter",
2050 enum {NONE = 0, PACKETS = 1, BYTES = 2, BOTH = 3} type = NONE;
2051 int teop = -1; bool teop_initialized = false; int bytecount_adjust = 0;
2052 table_type_t table_type() const override { return COUNTER; }
2053 template <class REGS>
2054 void write_merge_regs_vt(REGS &regs, MatchTable *match, int type, int bus,
2055 const std::vector<Call::Arg> &args);
2056 FOR_ALL_REGISTER_SETS(TARGET_OVERLOAD, void write_merge_regs,
2057 (mau_regs & regs, MatchTable *match, int type, int bus,
2058 const std::vector<Call::Arg> &args),
2059 override)
2060
2061 template <class REGS>
2062 void setup_teop_regs(REGS &regs, int stats_group_index);
2063 template <class REGS> void write_alu_vpn_range(REGS &regs);
2064 template <class REGS> void setup_teop_regs_2(REGS &regs, int stats_group_index);
2065 template <class REGS> void write_alu_vpn_range_2(REGS &regs);
2066
2067 struct lrt_params { // largest recent with threshold paramters
2068 int lineno;
2069 int64_t threshold;
2070 int interval;
2071 lrt_params(int l, int64_t t, int i) : lineno(l), threshold(t), interval(i) {}
2072 explicit lrt_params(const value_t &);
2073 };
2074 std::vector<lrt_params> lrt; public
2075 : int home_row() const override { return layout.at(0).row; } int direct_shiftcount()
2076 const override;
2077 int indirect_shiftcount() const override;
2078 unsigned determine_shiftcount(Table::Call &call, int group, unsigned word, int tcam_shift)
2079 const override;
2080 int address_shift() const override;
2081 bool run_at_eop() override { return (type & BYTES) != 0; } bool adr_mux_select_stats()
2082 override { return true; } int unitram_type() override { return UnitRam::STATISTICS; }
2083)
2084// clang-format on
2085
2086// clang-format off
2087DECLARE_TABLE_TYPE(
2088 MeterTable, Synth2Port, "meter", int red_nodrop_value = -1; int red_drop_value = -1;
2089 int green_value = 0; int yellow_value = 1; int red_value = 3; int profile = 0; int teop = -1;
2090 bool teop_initialized = false; int bytecount_adjust = 0;
2091 enum {NONE = 0, STANDARD = 1, LPF = 2, RED = 3} type = NONE;
2092 enum {NONE_ = 0, PACKETS = 1, BYTES = 2} count = NONE_; std::vector<Layout> color_maprams;
2093 table_type_t table_type() const override { return METER; } template <class REGS>
2094 void write_merge_regs_vt(REGS &regs, MatchTable *match, int type, int bus,
2095 const std::vector<Call::Arg> &args);
2096 template <class REGS> void meter_color_logical_to_phys(REGS &regs, int logical_id, int alu);
2097 FOR_ALL_REGISTER_SETS(TARGET_OVERLOAD, void write_merge_regs,
2098 (mau_regs & regs, MatchTable *match, int type, int bus,
2099 const std::vector<Call::Arg> &args),
2100 override)
2101
2102 template <class REGS>
2103 void setup_teop_regs(REGS &regs, int meter_group_index);
2104 template <class REGS> void write_alu_vpn_range(REGS &regs);
2105 template <class REGS> void write_regs_home_row(REGS &regs, unsigned row);
2106 template <class REGS> void write_mapram_color_regs(REGS &regs, bool &push_on_overflow);
2107
2108 template <class REGS> void setup_teop_regs_2(REGS &regs, int stats_group_index);
2109 template <class REGS> void write_alu_vpn_range_2(REGS &regs);
2110
2111 int sweep_interval = 2; public
2112 : enum {NO_COLOR_MAP, IDLE_MAP_ADDR, STATS_MAP_ADDR} color_mapram_addr = NO_COLOR_MAP;
2113 int direct_shiftcount() const override; int indirect_shiftcount() const override;
2114 int address_shift() const override; bool color_aware = false;
2115 bool color_aware_per_flow_enable = false; bool color_used = false;
2116 int pre_color_hash_dist_unit = -1; int pre_color_bit_lo = -1;
2117 bool run_at_eop() override { return type == STANDARD; } int unitram_type() override {
2118 return UnitRam::METER;
2119 } int home_row() const override { return layout.at(0).row | 3; } unsigned meter_group()
2120 const { return layout.at(0).row / 4U; } bool uses_colormaprams() const override {
2121 return !color_maprams.empty();
2122 } unsigned determine_shiftcount(Table::Call &call, int group, unsigned word, int tcam_shift)
2123 const override;
2124 void add_cfg_reg(json::vector &cfg_cache, std::string full_name, std::string name, unsigned val,
2125 unsigned width);
2126 Layout::bus_type_t default_bus_type() const override; int default_pfe_adjust() const override {
2127 return color_aware ? -METER_TYPE_BITS : 0;
2128 } void set_color_used() override { color_used = true; } void set_output_used() override {
2129 output_used = true;
2130 } int color_shiftcount(Table::Call &call, int group, int tcam_shift) const override;
2131 template <class REGS>
2132 void setup_exact_shift(REGS &merge, int bus, int group, int word, int word_group,
2133 Call &meter_call, Call &color_call);
2134 template <class REGS>
2135 void setup_tcam_shift(REGS &merge, int bus, int tcam_shift, Call &meter_call, Call &color_call);
2136 template <class REGS> void write_color_regs(REGS &regs, MatchTable *match, int type, int bus,
2137 const std::vector<Call::Arg> &args);
2138)
2139// clang-format on
2140
2141namespace StatefulAlu {
2142struct TMatchOP;
2143struct TMatchInfo {
2144 const Table::Actions::Action *act;
2145 const TMatchOP *op;
2146};
2147
2148Instruction *genNoop(StatefulTable *tbl, Table::Actions::Action *act);
2149} // namespace StatefulAlu
2150
2151// clang-format off
2152DECLARE_TABLE_TYPE(StatefulTable, Synth2Port, "stateful",
2153 table_type_t table_type() const override { return STATEFUL; }
2154 bool setup_jbay(const pair_t &kv);
2155 template<class REGS> void write_action_regs_vt(REGS &regs, const Actions::Action *);
2156 FOR_ALL_REGISTER_SETS(TARGET_OVERLOAD,
2157 void write_action_regs, (mau_regs &regs, const Actions::Action *act), override)
2158 template<class REGS> void write_merge_regs_vt(REGS &regs, MatchTable *match, int type, int bus,
2159 const std::vector<Call::Arg> &args);
2160 template<class REGS> void write_logging_regs(REGS &regs);
2161 FOR_ALL_REGISTER_SETS(TARGET_OVERLOAD,
2162 void write_merge_regs, (mau_regs &regs, MatchTable *match, int type,
2163 int bus, const std::vector<Call::Arg> &args), override)
2164 template<class REGS> void write_tofino2_common_regs(REGS &regs);
2165 struct const_info_t {
2166 int lineno;
2167 int64_t value;
2168 bool is_param;
2169 std::string param_name;
2170 unsigned param_handle;
2171 static unsigned unique_register_param_handle;
2172 const_info_t() = default;
2173 const_info_t(int lineno,
2174 int64_t value,
2175 bool is_param = false,
2176 std::string param_name = "",
2177 unsigned param_handle = 0)
2178 : lineno(lineno), value(value), is_param(is_param),
2179 param_name(param_name), param_handle(param_handle) {
2180 if (is_param) this->param_handle = unique_register_param_handle++;
2181 }
2182 };
2183 std::vector<const_info_t> const_vals;
2184 struct MathTable {
2185 int lineno = -1;
2186 std::vector<int> data;
2187 bool invert = false;
2188 int shift = 0, scale = 0;
2189 explicit operator bool() { return lineno >= 0; }
2190 void check();
2191 } math_table;
2192 bool dual_mode = false;
2193 bool offset_vpn = false;
2194 bool address_used = false;
2195 int meter_adr_shift = 0;
2196 int stateful_counter_mode = 0;
2197 int watermark_level = 0;
2198 int watermark_pop_not_push = 0;
2199 uint64_t initial_value_lo = 0;
2200 uint64_t initial_value_hi = 0;
2201 unsigned data_bytemask = 0;
2202 unsigned hash_bytemask = 0;
2203 int logvpn_lineno = -1;
2204 int logvpn_min = -1, logvpn_max = -1;
2205 int pred_shift = 0, pred_comb_shift = 0;
2206 int stage_alu_id = -1;
2207 Ref underflow_action, overflow_action;
2208
2209 // NOLINTNEXTLINE (whitespace/indent)
2210 public:
2211 Ref bound_selector;
2212 unsigned phv_byte_mask = 0;
2213 std::vector<Ref> sbus_learn, sbus_match;
2214 enum { SBUS_OR = 0, SBUS_AND = 1 } sbus_comb = SBUS_OR;
2215 int phv_hash_shift = 0;
2216 bitvec phv_hash_mask = bitvec(0, 128);
2217 Instruction *output_lmatch = nullptr; // output instruction using lmatch
2218 bitvec clear_value;
2219 uint32_t busy_value = 0;
2220 bool divmod_used = false;
2221 int instruction_set() override { return 1; /* STATEFUL_ALU */ }
2222 int direct_shiftcount() const override;
2223 int indirect_shiftcount() const override;
2224 int address_shift() const override;
2225 int unitram_type() override { return UnitRam::STATEFUL; }
2226 int get_const(int lineno, int64_t v);
2227 bool is_dual_mode() const { return dual_mode; }
2228 int alu_size() const { return 1 << std::min(5U, format->log2size - is_dual_mode()); }
2229 int home_row() const override { return layout.at(0).row | 3; }
2230 unsigned meter_group() const { return layout.at(0).row/4U; }
2231 unsigned determine_shiftcount(Table::Call &call, int group, unsigned word,
2232 int tcam_shift) const override;
2233 unsigned per_flow_enable_bit(MatchTable *m = nullptr) const override;
2234 void set_address_used() override { address_used = true; }
2235 void set_output_used() override { output_used = true; }
2236 void parse_register_params(int idx, const value_t &val);
2237 int64_t get_const_val(int index) const { return const_vals.at(index).value; }
2238 Actions::Action *action_for_table_action(const MatchTable *tbl, const Actions::Action *) const;
2239 OVERLOAD_FUNC_FOREACH(REGISTER_SET, static int, parse_counter_mode, (const value_t &v), (v))
2240 OVERLOAD_FUNC_FOREACH(REGISTER_SET, void, set_counter_mode, (int mode), (mode))
2241 OVERLOAD_FUNC_FOREACH(REGISTER_SET,
2242 void, gen_tbl_cfg, (json::map &tbl, json::map &stage_tbl) const, (tbl, stage_tbl))
2244
2245 bool p4c_5192_workaround(const Actions::Action *) const;
2246)
2247// clang-format on
2248
2249#endif /* BACKENDS_TOFINO_BF_ASM_TABLES_H_ */
Definition action_bus.h:147
Definition bf-asm/alloc.h:48
Definition tables.h:1969
Definition bf-asm/input_xbar.h:58
Definition match_source.h:32
Definition bitvec.h:120
Definition ordered_map.h:32
Definition p4_table.h:39
Definition bf-asm/phv.h:186
Definition bf-asm/phv.h:32
Definition stage.h:123
Definition tables.h:536
void add_action_format(const Table *, json::map &) const
Definition tables.cpp:2476
Definition tables.h:274
Definition tables.h:229
Definition tables.h:98
bool validate_instruction(Table::Call &call) const
Definition tables.cpp:593
virtual void add_reference_table(json::vector &table_refs, const Table::Call &c) const
Definition tables.cpp:2881
void get_cjson_source(const std::string &field_name, std::string &source, int &start_bit) const
Definition tables.cpp:2955
static bool allow_bus_sharing(Table *t1, Table *t2)
Definition tables.cpp:887
static bool allow_ram_sharing(const Table *t1, const Table *t2)
Definition tables.cpp:873
virtual void add_field_to_pack_format(json::vector &field_list, unsigned basebit, std::string name, const Table::Format::Field &field, const Table::Actions::Action *act) const
Definition tables.cpp:3030
Definition backends/tofino/bf-asm/json.h:300
Definition backends/tofino/bf-asm/json.h:222
void error(const char *format, Args &&...args)
Report an error with the given message.
Definition lib/error.h:58
Definition salu_inst.cpp:29
Definition bson.cpp:69
STL namespace.
Definition action_bus.h:28
Definition tables.h:1095
Definition bf-asm/input_xbar.h:31
Definition hash_dist.h:32
Definition bf-asm/input_xbar.h:71
Definition instruction.h:26
Definition tables.h:1466
Definition tables.h:71
virtual const char * desc() const
Definition tables.cpp:34
Definition tables.h:1234
Definition tables.h:538
bool immediate_conditional(int lo, int sz, std::string &condition) const
Definition tables.cpp:1968
void setup_mod_cond_values(value_t &map)
Definition tables.cpp:1523
void check_conditional(Table::Format::Field &field) const
Definition tables.cpp:1939
void gen_simple_tbl_cfg(json::vector &) const
Definition tables.cpp:2434
Definition tables.h:409
Definition tables.h:287
void set_field_bits(bitvec &bitset) const
mark all bits from the field in
Definition tables.h:330
Definition tables.h:100
Definition tables.h:183
Definition tables.h:516
Definition tables.h:1241
Definition tables.h:1262
Definition tables.h:1403
Definition asm-types.h:150
Definition asm-types.h:114