18#ifndef BACKENDS_TOFINO_BF_ASM_PARSER_TOFINO_JBAY_H_
19#define BACKENDS_TOFINO_BF_ASM_PARSER_TOFINO_JBAY_H_
25#include "backends/tofino/bf-asm/target.h"
26#include "lib/bitvec.h"
34 PARSER_STATE_MASK = 0xff,
35 PARSER_TCAM_DEPTH = 256,
36 PARSER_CHECKSUM_ROWS = 32,
37 PARSER_CTRINIT_ROWS = 16,
38 PARSER_INPUT_BUFFER_SIZE = 32,
39 PARSER_SRC_MAX_IDX = 63,
40 PARSER_MAX_CLOTS = 64,
41 PARSER_MAX_CLOT_LENGTH = 64,
49 void write_config(RegisterSetBase ®s,
json::map &
json,
bool legacy =
true)
override;
51 void write_config(REGS &,
json::map &,
bool legacy =
true);
54 int lineno = -1, addr = -1;
55 int add = 0, mask = 255, rot = 0, max = 255, src = -1;
56 CounterInit(gress_t,
pair_t);
57 void pass1(Parser *) {}
60 void write_config(REGS &, gress_t,
int);
61 bool equiv(
const CounterInit &)
const;
63 struct PriorityUpdate {
64 int lineno = -1, offset = -1, shift = -1, mask = -1;
66 explicit PriorityUpdate(
const value_t &data);
67 bool parse(
const value_t &exp,
int what = 0);
68 explicit operator bool()
const {
return lineno >= 0; }
70 void write_config(REGS &);
74 int inc = -1, dec = -1, max = -1, interval = -1;
75 void parse(
const VECTOR(
pair_t) &);
76 explicit operator bool()
const {
return lineno >= 0; }
78 void write_config(REGS &, gress_t);
89 std::vector<State *> ptr;
90 Ref() : lineno(-1) { pattern.word0 = pattern.word1 = 0; }
91 Ref &operator=(
const value_t &);
92 explicit Ref(
value_t &v) { *
this = v; }
93 operator bool()
const {
return ptr.size() > 0; }
94 State *operator->()
const {
95 BUG_CHECK(ptr.size() == 1,
"pointer size must be 1, got %d", ptr.size());
98 State *operator*()
const {
99 BUG_CHECK(ptr.size() == 1,
"pointer size must be 1, got %d", ptr.size());
102 bool operator==(
const Ref &a)
const {
return name == a.name && pattern == a.pattern; }
103 void check(gress_t,
Parser *, State *);
104 std::vector<State *>::const_iterator begin()
const {
return ptr.begin(); }
105 std::vector<State *>::const_iterator end()
const {
return ptr.end(); }
112 enum { USE_SAVED = 0x7fff };
114 short ctr_zero, ctr_neg;
117 MatchKey() : lineno(0), specified(0), ctr_zero(-1), ctr_neg(-1), width(0) {
118 for (
auto &a : data) a.bit = a.byte = -1;
121 int setup_match_el(
int,
value_t &);
122 void preserve_saved(
unsigned mask);
123 template <
class REGS>
127 int add_byte(
int,
int,
bool use_saved =
false);
131 unsigned b8 = 0, b16 = 0, b32 = 0;
141 State *state =
nullptr;
143 std::string value_set_name;
144 int value_set_size = 0;
145 int value_set_handle = -1;
146 int offset_inc = 0, shift = 0, buf_req = -1;
147 int disable_partial_hdr_err = -1, partial_hdr_err_proc = -1;
148 bool offset_rst =
false;
149 int intr_md_bits = 0;
151 int ctr_imm_amt = 0, ctr_ld_src = 0, ctr_load = 0;
152 bool ctr_stack_push =
false, ctr_stack_upd_w_top =
false, ctr_stack_pop =
false;
154 CounterInit *ctr_instr =
nullptr;
156 PriorityUpdate priority;
166 std::vector<const Phv::Ref *> narrow_to_wide_32b_16;
168 std::vector<const Phv::Ref *> narrow_to_wide_32b_8;
170 std::vector<const Phv::Ref *> narrow_to_wide_16b_8;
172 enum flags_t { OFFSET = 1, ROTATE = 2 };
179 Save(gress_t, Match *m,
int l,
int h,
value_t &data,
int flgs = 0);
180 template <
class REGS>
181 int write_output_config(REGS &,
void *,
unsigned &,
int,
int)
const;
183 std::vector<Save *> save;
186 Match *match =
nullptr;
190 Set(gress_t gress, Match *m,
value_t &data,
int v,
int flgs = 0);
191 template <
class REGS>
192 void write_output_config(REGS &,
void *,
unsigned &,
int,
int)
const;
193 bool merge(gress_t,
const Set &a);
194 bool operator==(
const Set &a)
const {
195 return where == a.where && what == a.what && flags == a.flags;
198 std::vector<Set *> set;
203 bool load_length =
false;
204 int start = -1, length = -1, length_shift = -1, length_mask = -1;
210 Clot(
const Clot &) =
delete;
211 Clot(Clot &&) =
delete;
212 bool parse_length(
const value_t &exp,
int what = 0);
213 template <
class PO_ROW>
214 void write_config(PO_ROW &,
int,
bool)
const;
217 Clot(gress_t,
const Clot &,
int);
219 std::vector<Clot *> clots;
220 std::vector<Checksum> csum;
222 struct FieldMapping {
224 std::string container_id;
229 std::vector<FieldMapping> field_mapping;
231 struct HdrLenIncStop {
233 unsigned final_amt = 0;
235 explicit HdrLenIncStop(
const value_t &data);
236 explicit operator bool()
const {
return lineno >= 0; }
237 template <
class PO_ROW>
238 void write_config(PO_ROW &)
const;
241 Match(
int lineno, gress_t, State *s,
match_t m, VECTOR(
pair_t) & data);
242 Match(
int lineno, gress_t, State *n);
244 if (ctr_instr)
delete ctr_instr;
246 void unmark_reachable(
Parser *, State *state,
bitvec &unreach);
247 void pass1(
Parser *pa, State *state);
248 void pass2(
Parser *pa, State *state);
249 template <
class REGS>
250 int write_load_config(REGS &,
Parser *, State *,
int)
const;
251 template <
class REGS>
252 void write_lookup_config(REGS &, State *,
int)
const;
253 template <
class EA_REGS>
254 void write_counter_config(EA_REGS &)
const;
255 template <
class REGS>
257 template <
class REGS>
259 template <
class REGS>
261 template <
class REGS>
264 template <
class REGS>
265 void write_saves(REGS ®s,
Match *def,
void *output_map,
int &max_off,
unsigned &used,
266 int csum_8b,
int csum_16b);
267 template <
class REGS>
268 void write_sets(REGS ®s,
Match *def,
void *output_map,
unsigned &used,
int csum_8b,
272 std::set<Match *> get_all_preds_impl(std::set<Match *> &visited);
279 std::vector<Match *> match;
281 std::set<Match *> pred;
282 bool ignore_max_depth =
false;
287 State(
int lineno,
const char *name, gress_t,
match_t stateno,
const VECTOR(
pair_t) & data);
289 void unmark_reachable(Parser *,
bitvec &);
290 void pass1(Parser *);
291 void pass2(Parser *);
292 template <
class REGS>
293 int write_lookup_config(REGS &, Parser *,
State *,
int,
const std::vector<State *> &);
294 template <
class REGS>
299 int lineno = -1, addr = -1, unit = -1;
303 unsigned add = 0, mask = 0, swap = 0, mul_2 = 0;
304 unsigned dst_bit_hdr_end_pos = 0;
305 bool start =
false, end =
false, shift =
false;
307 Checksum(gress_t,
pair_t);
308 bool equiv(
const Checksum &)
const;
311 template <
class REGS>
312 void write_config(REGS &,
Parser *);
313 template <
class REGS>
317 template <
typename ROW>
318 void write_tofino_row_config(ROW &row);
319 template <
typename ROW>
320 void write_row_config(ROW &row);
330 std::map<std::string, State *> states;
331 std::vector<State *> all;
332 std::map<State::Match *, int> match_to_row;
337 int priority[4] = {0};
338 int pri_thresh[4] = {0, 0, 0, 0};
339 int tcam_row_use = 0;
340 Phv::Ref parser_error;
346 std::vector<Phv::Ref> ghost_parser;
347 unsigned ghost_pipe_mask = 0xf;
348 bitvec (&phv_use)[2];
349 bitvec phv_allow_bitwise_or, phv_allow_clear_on_write;
350 bitvec phv_init_valid;
351 int hdr_len_adj = 0, meta_opt = 0;
352 std::vector<std::array<Checksum *, PARSER_CHECKSUM_ROWS>> checksum_use;
353 std::array<CounterInit *, PARSER_CTRINIT_ROWS> counter_init = {};
354 static std::map<gress_t, std::map<std::string, std::vector<State::Match::Clot *>>> clots;
355 static std::array<std::vector<State::Match::Clot *>, PARSER_MAX_CLOTS> clot_use;
356 static unsigned max_handle;
357 int parser_handle = -1;
358 RateLimit rate_limit;
360 Parser(bitvec (&phv_use)[2], gress_t gr,
int idx)
361 : gress(gr), parser_no(idx), phv_use(phv_use) {
362 if (gress == INGRESS) {
363 parser_depth_max_bytes = Target::PARSER_DEPTH_MAX_BYTES_INGRESS();
364 parser_depth_min_bytes = Target::PARSER_DEPTH_MIN_BYTES_INGRESS();
366 parser_depth_max_bytes = Target::PARSER_DEPTH_MAX_BYTES_EGRESS();
367 parser_depth_min_bytes = Target::PARSER_DEPTH_MIN_BYTES_EGRESS();
371 template <
class REGS>
372 void gen_configuration_cache(REGS &, json::vector &cfg_cache);
373 static int clot_maxlen(gress_t gress,
unsigned tag) {
374 auto &vec = clot_use[tag];
375 return vec.empty() ? -1 : vec.at(0)->max_length;
377 static int clot_maxlen(gress_t gress, std::string tag) {
378 if (clots.count(gress) && clots.at(gress).count(tag))
379 return clots.at(gress).at(tag).at(0)->max_length;
382 static int clot_tag(gress_t gress, std::string tag) {
383 if (clots.count(gress) && clots.at(gress).count(tag))
384 return clots.at(gress).at(tag).at(0)->tag;
388 static const char *match_key_loc_name(
int loc);
389 static int match_key_loc(
const char *key);
390 static int match_key_loc(value_t &key,
bool errchk =
true);
391 static int match_key_size(
const char *key);
401 static unsigned next_handle() {
404 return max_handle++ << 12 | unique_table_offset << 20 | 15 << 24;
408 static std::map<std::string, unsigned> parser_handles;
409 static unsigned get_parser_handle(std::string phase0Table) {
410 for (
auto p : Parser::parser_handles) {
411 auto parser_name = p.first;
412 if (phase0Table.find(parser_name) != std::string::npos)
return p.second;
417 template <
class REGS>
418 void *setup_phv_output_map(REGS &, gress_t,
int);
420 State *get_start_state() {
421 std::vector<std::string> startNames = {
"start",
"START",
"$entry_point.start",
423 for (
auto n : startNames) {
424 if (states.count(n))
return states.at(n);
429 int get_prsr_max_dph();
430 int get_header_stack_size_from_valid_bits(std::vector<State::Match::Set *> sets);
433 void print_all_paths();
436 template <
class REGS>
437 void mark_unused_output_map(REGS &,
void *,
unsigned);
438 void define_state(gress_t gress, pair_t &kv);
439 void output_default_ports(json::vector &vec, bitvec port_use);
440 int state_prsr_dph_max(
const State *s);
441 int state_prsr_dph_max(
const State *s, std::map<
const State *, std::pair<int, int>> &visited,
443 int parser_depth_max_bytes, parser_depth_min_bytes;
446class AsmParser :
public BaseAsmParser {
447 std::vector<Parser *> parser[2];
449 std::vector<Phv::Ref> ghost_parser;
452 unsigned ghost_pipe_mask = 0xf;
453 void start(
int lineno, VECTOR(
value_t) args)
override;
455 void process()
override;
460 AsmParser() : BaseAsmParser(
"parser") {};
464 std::vector<Parser *> test_get_parser(gress_t gress);
468void Parser::PriorityUpdate::write_config(REGS &action_row) {
470 action_row.pri_upd_type = 1;
471 action_row.pri_upd_src = offset;
472 action_row.pri_upd_en_shr = shift;
473 action_row.pri_upd_val_mask = mask;
475 action_row.pri_upd_type = 0;
476 action_row.pri_upd_en_shr = 1;
477 action_row.pri_upd_val_mask = mask;
483void Parser::RateLimit::write_config(::Tofino::regs_pipe ®s, gress_t gress);
485void Parser::RateLimit::write_config(REGS ®s, gress_t gress) {
486 if (gress == INGRESS) {
487 auto &ctrl = regs.pardereg.pgstnreg.parbreg.left.i_phv_rate_ctrl;
489 ctrl.interval = interval;
491 }
else if (gress == EGRESS) {
492 auto &ctrl = regs.pardereg.pgstnreg.parbreg.right.e_phv_rate_ctrl;
494 ctrl.interval = interval;
500void Parser::State::MatchKey::write_config(REGS &, json::vector &) {
506void Parser::State::Match::write_saves(REGS ®s, Match *def,
void *output_map,
int &max_off,
507 unsigned &used,
int csum_8b,
int csum_16b) {
509 for (
auto s : save) s->flags |= OFFSET;
512 std::max(max_off, s->write_output_config(regs, output_map, used, csum_8b, csum_16b));
514 for (
auto &s : def->save)
515 max_off = std::max(max_off,
516 s->write_output_config(regs, output_map, used, csum_8b, csum_16b));
520void Parser::State::Match::write_sets(REGS ®s, Match *def,
void *output_map,
unsigned &used,
521 int csum_8b,
int csum_16b) {
523 for (
auto s : set) s->flags |= ROTATE;
524 for (
auto s : set) s->write_output_config(regs, output_map, used, csum_8b, csum_16b);
526 for (
auto s : def->set) s->write_output_config(regs, output_map, used, csum_8b, csum_16b);
530void Parser::State::Match::write_common_row_config(REGS ®s, Parser *pa,
State *state,
int row,
531 Match *def, json::map &ctxt_json) {
533 write_lookup_config(regs, state, row);
535 auto &ea_row = regs.memory[state->gress].ml_ea_row[row];
536 if (ctr_instr || ctr_load || ctr_imm_amt || ctr_stack_pop) {
537 write_counter_config(ea_row);
539 def->write_counter_config(ea_row);
542 max_off = std::max(max_off,
int(ea_row.shift_amt = shift) - 1);
544 max_off = std::max(max_off,
int(ea_row.shift_amt = def->shift) - 1);
545 max_off = std::max(max_off, write_load_config(regs, pa, state, row));
546 if (
auto &next = (!this->next && def) ? def->next : this->next) {
547 std::vector<State *> prev;
548 for (
auto n : next) {
549 max_off = std::max(max_off, n->write_lookup_config(regs, pa, state, row, prev));
552 const match_t &n = next.pattern ? next.pattern : next->stateno;
553 ea_row.nxt_state = n.word1;
554 ea_row.nxt_state_mask = ~(n.word0 & n.word1) & PARSER_STATE_MASK;
559 auto &action_row = regs.memory[state->gress].po_action_row[row];
560 for (
auto &c : csum) {
561 action_row.csum_en[c.unit] = 1;
562 action_row.csum_addr[c.unit] = c.addr;
564 if (offset_inc || offset_rst) {
565 action_row.dst_offset_inc = offset_inc;
566 action_row.dst_offset_rst = offset_rst;
568 action_row.dst_offset_inc = def->offset_inc;
569 action_row.dst_offset_rst = def->offset_rst;
571 if (priority) priority.write_config(action_row);
572 if (hdr_len_inc_stop) hdr_len_inc_stop.write_config(action_row);
574 void *output_map = pa->setup_phv_output_map(regs, state->gress, row);
578 for (
auto &c : csum) {
579 c.write_output_config(regs, pa,
this, output_map, used);
580 if (c.type == 0 && c.dest) {
581 if (c.dest->reg.size == 8)
583 else if (c.dest->reg.size == 16)
588 if (options.target == TOFINO) {
589 write_sets(regs, def, output_map, used, csum_8b, csum_16b);
590 write_saves(regs, def, output_map, max_off, used, csum_8b, csum_16b);
592 write_sets(regs, def, output_map, used, 0, 0);
593 write_saves(regs, def, output_map, max_off, used, 0, 0);
597 for (
auto *c : clots) c->write_config(action_row, clot_unit++, offset_inc > 0);
599 for (
auto *c : def->clots) c->write_config(action_row, clot_unit++, offset_inc > 0);
600 pa->mark_unused_output_map(regs, output_map, used);
603 buf_req = max_off + 1;
604 BUG_CHECK(buf_req <= 32,
"Buffer requirement too large: %d", buf_req);
606 ea_row.buf_req = buf_req;
610void Parser::State::Match::write_row_config(REGS ®s, Parser *pa,
State *state,
int row,
611 Match *def, json::map &ctxt_json) {
612 write_common_row_config(regs, pa, state, row, def, ctxt_json);
616void Parser::State::Match::write_config(REGS ®s, Parser *pa,
State *state, Match *def,
617 json::map &ctxt_json) {
620 if ((row = --pa->tcam_row_use) < 0) {
622 error(state->lineno,
"Ran out of tcam space in %sgress parser",
623 state->gress ?
"e" :
"in");
626 ctxt_json[
"tcam_rows"].to<json::vector>().push_back(row);
627 write_row_config(regs, pa, state, row, def, ctxt_json);
628 pa->match_to_row[
this] = row;
629 }
while (++count < value_set_size);
633void Parser::State::Match::write_config(REGS ®s, json::vector &vec) {
634 int select_statement_bit = 0;
635 for (
auto f : field_mapping) {
636 json::map container_cjson;
637 container_cjson[
"container_width"] = Parser::match_key_size(f.container_id.c_str());
639 int container_hardware_id = Parser::match_key_loc(f.container_id.c_str());
640 container_cjson[
"container_hardware_id"] = container_hardware_id;
642 container_cjson[
"mask"] = (1 << (f.hi - f.lo + 1)) - 1;
643 json::vector field_mapping_cjson;
644 for (
auto i = f.lo; i <= f.hi; i++) {
646 field_map[
"register_bit"] = i;
647 field_map[
"field_name"] = f.where.name();
648 field_map[
"start_bit"] = i;
649 field_map[
"select_statement_bit"] = select_statement_bit++;
650 field_mapping_cjson.push_back(field_map.clone());
652 container_cjson[
"field_mapping"] = field_mapping_cjson.clone();
653 vec.push_back(container_cjson.clone());
658void Parser::State::write_config(REGS ®s, Parser *pa, json::vector &ctxt_json) {
659 LOG2(gress <<
" state " << name <<
" (" << stateno <<
')');
660 for (
auto i : match) {
661 bool uses_pvs =
false;
662 json::map state_cjson;
663 state_cjson[
"parser_name"] = name;
664 i->write_config(regs, state_cjson[
"match_registers"]);
665 if (i->value_set_size > 0) uses_pvs =
true;
666 i->write_config(regs, pa,
this, def, state_cjson);
667 state_cjson[
"uses_pvs"] = uses_pvs;
668 if (def) def->write_config(regs, pa,
this, 0, state_cjson);
670 state_cjson[
"pvs_name"] = i->value_set_name;
671 if (i->value_set_handle < 0)
672 error(lineno,
"Invalid handle for parser value set %s", i->value_set_name.c_str());
673 auto pvs_handle_full = i->value_set_handle;
674 state_cjson[
"pvs_handle"] = pvs_handle_full;
676 for (
auto idx : MatchIter(stateno)) {
677 state_cjson[
"parser_state_id"] = idx;
678 ctxt_json.push_back(state_cjson.clone());
683template <
typename ROW>
684void Parser::Checksum::write_tofino_row_config(ROW &row) {
687 row.dst = dest->reg.parser_id();
690 row.dst_bit_hdr_end_pos = dst_bit_hdr_end_pos;
693 for (
auto &el : row.mask) el = (mask >> rsh++) & 1;
697 for (
auto &el : row.swap) el = (swap >> rsh++) & 1;
702void Parser::Checksum::write_row_config(ROW &row) {
703 write_tofino_row_config(row);
705 for (
auto &el : row.mul_2) el = (mul_2 >> rsh++) & 1;
709bitvec expand_parser_groups(bitvec phvs);
710bitvec remove_nonparser(bitvec phvs);
711void setup_jbay_ownership(bitvec phv_use[2], checked_array<128, ubits<1>> &left,
712 checked_array<128, ubits<1>> &right, checked_array<256, ubits<1>> &main_i,
713 checked_array<256, ubits<1>> &main_e);
714void setup_jbay_no_multi_write(bitvec phv_allow_bitwise_or, bitvec phv_allow_clear_on_write,
715 checked_array<256, ubits<1>> &nmw_i,
716 checked_array<256, ubits<1>> &nmw_e);
717void setup_jbay_clear_on_write(bitvec phv_allow_clear_on_write, checked_array<128, ubits<1>> &left,
718 checked_array<128, ubits<1>> &right,
719 checked_array<256, ubits<1>> &main_i,
720 checked_array<256, ubits<1>> &main_e);
Base class of Tofino parser in assembler.
Definition tofino/bf-asm/parser.h:32
Definition bf-asm/phv.h:186
Definition backends/tofino/bf-asm/json.h:300
Definition backends/tofino/bf-asm/json.h:222
Representation of the Tofino 1/2 parser in assembler.
Definition parser-tofino-jbay.h:48
void error(const char *format, Args &&...args)
Report an error with the given message.
Definition lib/error.h:58
Definition parser-tofino-jbay.h:139
std::set< Match * > get_all_preds()
Definition parser-tofino-jbay.cpp:1851
bool has_narrow_to_wide_extract
Definition parser-tofino-jbay.h:164
Definition parser-tofino-jbay.h:107
Definition parser-tofino-jbay.h:130
Definition parser-tofino-jbay.h:85
Definition parser-tofino-jbay.h:84
Definition asm-types.h:150
Definition asm-types.h:114