P4C
The P4 Compiler
Loading...
Searching...
No Matches
jbay/stage.cpp
1
17
18/* mau stage template specializations for jbay -- #included directly in top-level stage.cpp */
19
20template <>
21void Stage::gen_configuration_cache(Target::JBay::mau_regs &regs, json::vector &cfg_cache) {
22 Stage::gen_configuration_cache_common(regs, cfg_cache);
23
24 static unsigned i_pdddelay;
25 static unsigned e_pdddelay;
26 unsigned reg_width = 8; // this means number of hex characters
27 std::string i_reg_value_str;
28 std::string e_reg_value_str;
29 std::string reg_fqname;
30 std::string reg_name;
31 unsigned reg_value;
32 std::string reg_value_str;
33
34 if (stageno != 0) {
35 if (i_pdddelay > regs.cfg_regs.amod_pre_drain_delay[INGRESS])
36 i_pdddelay = regs.cfg_regs.amod_pre_drain_delay[INGRESS];
37 if (e_pdddelay > regs.cfg_regs.amod_pre_drain_delay[EGRESS])
38 e_pdddelay = regs.cfg_regs.amod_pre_drain_delay[EGRESS];
39
40 if (stageno == AsmStage::numstages() - 1) {
41 // 64 is due to number of CSR's
42 i_pdddelay += (7 + 64);
43 i_reg_value_str = int_to_hex_string(i_pdddelay, reg_width);
44 e_pdddelay += (7 + 64);
45 e_reg_value_str = int_to_hex_string(e_pdddelay, reg_width);
46
47 add_cfg_reg(cfg_cache, "pardereg.pgstnreg.parbreg.left.i_wb_ctrl", "left_i_wb_ctrl",
48 i_reg_value_str);
49 add_cfg_reg(cfg_cache, "pardereg.pgstnreg.parbreg.right.e_wb_ctrl", "right_e_wb_ctrl",
50 e_reg_value_str);
51 }
52 }
53
54 // meter_ctl
55 auto &meter_ctl = regs.rams.map_alu.meter_group;
56 for (int i = 0; i < 4; i++) {
57 reg_fqname = "mau[" + std::to_string(stageno) + "].rams.map_alu.meter_group[" +
58 std::to_string(i) + "]" + ".meter.meter_ctl";
59 reg_name = "stage_" + std::to_string(stageno) + "_meter_ctl_" + std::to_string(i);
60 reg_value = meter_ctl[i].meter.meter_ctl;
61 if ((reg_value != 0) || (options.match_compiler)) {
62 reg_value_str = int_to_hex_string(reg_value, reg_width);
63 add_cfg_reg(cfg_cache, reg_fqname, reg_name, reg_value_str);
64 }
65 }
66}
67
68static void addvec(json::vector &vec, ubits_base &val, uint32_t extra = 0) {
69 vec.push_back(val | extra);
70}
71static void addvec(json::vector &vec, uint32_t val, uint32_t extra = 0) {
72 vec.push_back(val | extra);
73}
74
75template <class T>
76static void addvec(json::vector &vec, checked_array_base<T> &array, uint32_t extra = 0) {
77 for (auto &el : array) addvec(vec, el, extra);
78}
79
80template <class REGS, class REG>
81static json::map make_reg_vec(REGS &regs, REG &reg, const char *name, uint32_t mask0,
82 uint32_t mask1, uint32_t mask2, uint32_t extra = 0) {
83 json::map rv;
84 rv["name"] = name;
85 rv["offset"] = regs.binary_offset(&reg);
86 addvec(rv["value"], reg, extra);
87 rv["mask"] = json::vector{json::number(mask0), json::number(mask1), json::number(mask2)};
88 return rv;
89}
90
91template <class REGS>
92void Stage::gen_mau_stage_extension(REGS &regs, json::map &extend) {
93 extend["last_programmed_stage"] = Target::NUM_MAU_STAGES() - 1;
94 json::vector &registers = extend["registers"] = json::vector();
95 registers.push_back(make_reg_vec(regs, regs.dp.phv_ingress_thread, "regs.dp.phv_ingress_thread",
96 0, 0x3ff, 0x3ff));
97 registers.push_back(make_reg_vec(regs, regs.dp.phv_ingress_thread_imem,
98 "regs.dp.phv_ingress_thread_imem", 0, 0x3ff, 0x3ff));
99 registers.push_back(make_reg_vec(regs, regs.dp.phv_egress_thread, "regs.dp.phv_egress_thread",
100 0, 0x3ff, 0x3ff));
101 registers.push_back(make_reg_vec(regs, regs.dp.phv_egress_thread_imem,
102 "regs.dp.phv_egress_thread_imem", 0, 0x3ff, 0x3ff));
103 registers.push_back(make_reg_vec(regs, regs.rams.match.adrdist.adr_dist_pipe_delay,
104 "regs.rams.match.adrdist.adr_dist_pipe_delay", 0, 0xf, 0xf));
105 typename std::remove_reference<
106 decltype(regs.rams.match.adrdist.deferred_eop_bus_delay[0])>::type mask0,
107 mask1;
108 mask0.eop_delay_fifo_en = mask1.eop_delay_fifo_en = 1;
109 mask0.eop_internal_delay_fifo = mask1.eop_internal_delay_fifo = 0x1f;
110 mask0.eop_output_delay_fifo = 0x1;
111 mask1.eop_output_delay_fifo = 0x1f;
112 BUG_CHECK(regs.rams.match.adrdist.deferred_eop_bus_delay[0].eop_output_delay_fifo &
113 regs.rams.match.adrdist.deferred_eop_bus_delay[1].eop_output_delay_fifo & 1,
114 "bad mask");
115 registers.push_back(make_reg_vec(regs, regs.rams.match.adrdist.deferred_eop_bus_delay,
116 "regs.rams.match.adrdist.deferred_eop_bus_delay", mask0, mask0,
117 mask1));
118 registers.push_back(make_reg_vec(regs, regs.dp.cur_stage_dependency_on_prev,
119 "regs.dp.cur_stage_dependency_on_prev", 0, 0x3, 0x3, 0x1));
120 registers.push_back(make_reg_vec(regs, regs.dp.next_stage_dependency_on_cur,
121 "regs.dp.next_stage_dependency_on_cur", 0x3, 0x3, 0, 0x1));
122 registers.push_back(make_reg_vec(regs, regs.rams.match.merge.mpr_bus_dep,
123 "regs.rams.match.merge.mpr_bus_dep", 0x3, 0x3, 0, 0x3));
124 registers.push_back(make_reg_vec(regs, regs.dp.pipelength_added_stages,
125 "regs.dp.pipelength_added_stages", 0, 0xf, 0xf));
126 registers.push_back(make_reg_vec(regs, regs.rams.match.merge.exact_match_delay_thread,
127 "regs.rams.match.merge.exact_match_delay_thread", 0, 0x3,
128 0x3));
129 BUG_CHECK((regs.rams.match.merge.mpr_thread_delay[0] & 1) == 0, "bad mask");
130 BUG_CHECK((regs.rams.match.merge.mpr_thread_delay[1] & 1) == 0, "bad mask");
131 registers.push_back(make_reg_vec(regs, regs.rams.match.merge.mpr_thread_delay,
132 "regs.rams.match.merge.mpr_thread_delay", 1, 1, 0x1f));
133}
134
135/* disable power gating configuration for specific MAU regs to weedout delay programming
136 * issues. We dont expect to call this function in the normal usage of JBay - this is
137 * only for emulator debug/bringup
138 */
139template <class REGS>
140static void disable_jbay_power_gating(REGS &regs) {
141 for (gress_t gress : Range(INGRESS, EGRESS)) {
142 regs.dp.mau_match_input_xbar_exact_match_enable[gress] |= 0x1;
143 regs.dp.xbar_hash.xbar.mau_match_input_xbar_ternary_match_enable[gress] |= 0x1;
144 }
145
146 auto &xbar_power_ctl = regs.dp.match_input_xbar_din_power_ctl;
147 auto &actionmux_power_ctl = regs.dp.actionmux_din_power_ctl;
148 for (int side = 0; side < 2; side++) {
149 for (int reg = 0; reg < 16; reg++) {
150 xbar_power_ctl[side][reg] |= 0x3FF;
151 actionmux_power_ctl[side][reg] |= 0x3FF;
152 }
153 }
154}
155
156template <>
157void Stage::write_regs(Target::JBay::mau_regs &regs, bool) {
158 write_common_regs<Target::JBay>(regs);
159 auto &merge = regs.rams.match.merge;
160 for (gress_t gress : Range(INGRESS, EGRESS)) {
161 if (stageno == 0) {
162 merge.predication_ctl[gress].start_table_fifo_delay0 = pred_cycle(gress) - 2;
163 merge.predication_ctl[gress].start_table_fifo_enable = 1;
164 } else if (stage_dep[gress] == MATCH_DEP) {
165 merge.predication_ctl[gress].start_table_fifo_delay0 =
166 this[-1].pipelength(gress) - this[-1].pred_cycle(gress) + pred_cycle(gress) - 3;
167 merge.predication_ctl[gress].start_table_fifo_enable = 1;
168 } else {
169 BUG_CHECK(stage_dep[gress] == ACTION_DEP, "bad stage dep");
170 merge.predication_ctl[gress].start_table_fifo_delay0 = 0;
171 merge.predication_ctl[gress].start_table_fifo_enable = 0;
172 }
173
174 if (stageno != 0)
175 regs.dp.cur_stage_dependency_on_prev[gress] = stage_dep[gress] != MATCH_DEP;
176
177 /* set stage0 dependency if explicitly set by the commandline option */
178 if (stageno == 0 && !options.stage_dependency_pattern.empty())
179 regs.dp.cur_stage_dependency_on_prev[gress] = stage_dep[gress] != MATCH_DEP;
180
181 if (stageno != AsmStage::numstages() - 1)
182 regs.dp.next_stage_dependency_on_cur[gress] = this[1].stage_dep[gress] != MATCH_DEP;
183 else if (AsmStage::numstages() < Target::NUM_MAU_STAGES())
184 regs.dp.next_stage_dependency_on_cur[gress] = 1;
185 auto &deferred_eop_bus_delay = regs.rams.match.adrdist.deferred_eop_bus_delay[gress];
186 deferred_eop_bus_delay.eop_internal_delay_fifo = pred_cycle(gress) + 2;
187 /* FIXME -- making this depend on the dependency of the next stage seems wrong */
188 if (stageno == AsmStage::numstages() - 1) {
189 if (AsmStage::numstages() < Target::NUM_MAU_STAGES())
190 deferred_eop_bus_delay.eop_output_delay_fifo = 1;
191 else
192 deferred_eop_bus_delay.eop_output_delay_fifo = pipelength(gress) - 2;
193 } else if (this[1].stage_dep[gress] == MATCH_DEP) {
194 deferred_eop_bus_delay.eop_output_delay_fifo = pipelength(gress) - 2;
195 } else {
196 deferred_eop_bus_delay.eop_output_delay_fifo = 1;
197 }
198 deferred_eop_bus_delay.eop_delay_fifo_en = 1;
199 if (stageno != AsmStage::numstages() - 1 && this[1].stage_dep[gress] == MATCH_DEP) {
200 merge.mpr_thread_delay[gress] = pipelength(gress) - pred_cycle(gress) - 4;
201 } else {
202 /* last stage in JBay must be always set as match-dependent on deparser */
203 if (stageno == AsmStage::numstages() - 1) {
204 merge.mpr_thread_delay[gress] = pipelength(gress) - pred_cycle(gress) - 4;
205 } else {
206 merge.mpr_thread_delay[gress] = 0;
207 }
208 }
209 }
210
211 for (gress_t gress : Range(INGRESS, EGRESS))
212 if (table_use[gress] & USE_TCAM)
213 regs.tcams.tcam_piped |= options.match_compiler ? 3 : 1 << gress;
214
215 for (gress_t gress : Range(INGRESS, EGRESS)) {
216 regs.cfg_regs.amod_pre_drain_delay[gress] = pipelength(gress) - 9;
217 if (this[1].stage_dep[gress] == MATCH_DEP)
218 regs.cfg_regs.amod_wide_bubble_rsp_delay[gress] = pipelength(gress) - 3;
219 else
220 regs.cfg_regs.amod_wide_bubble_rsp_delay[gress] = 0;
221 }
222 /* Max re-request limit with a long interval. Parb is going to have a large
223 * gap configured to minimize traffic hits during configuration this means
224 * that individual stages may not get their bubbles and will need to retry. */
225 regs.cfg_regs.amod_req_interval = 6732;
226 regs.cfg_regs.amod_req_limit = 15;
227
228 if (stageno == 0) {
229 /* MFerrera: "After some debug on the emulator, we've found a programming issue due to
230 * incorrect documentation and CSR description of match_ie_input_mux_sel in JBAY"
231 * MAU Stage 0 must always be configured to source iPHV from Parser-Arbiter
232 * Otherwise, MAU stage 0 is configured as match-dependent on Parser-Arbiter */
233 regs.dp.match_ie_input_mux_sel |= 3;
234 }
235
236 merge.pred_stage_id = stageno;
237 if (long_branch_terminate) merge.pred_long_brch_terminate = long_branch_terminate;
238 for (gress_t gress : Range(INGRESS, GHOST)) {
239 if (long_branch_thread[gress])
240 merge.pred_long_brch_thread[gress] = long_branch_thread[gress];
241 }
242
243 for (gress_t gress : Range(INGRESS, GHOST)) {
244 merge.mpr_stage_id[gress] = mpr_stage_id[gress];
245 for (int id = 0; id < LOGICAL_TABLES_PER_STAGE; ++id) {
246 merge.mpr_next_table_lut[gress][id] = mpr_next_table_lut[gress][id];
247 }
248 }
249 for (int id = 0; id < LOGICAL_TABLES_PER_STAGE; ++id) {
250 merge.mpr_glob_exec_lut[id] = mpr_glob_exec_lut[id];
251 }
252 for (int id = 0; id < MAX_LONGBRANCH_TAGS; ++id) {
253 merge.mpr_long_brch_lut[id] = mpr_long_brch_lut[id];
254 }
255 merge.mpr_always_run = mpr_always_run;
256
257 if (stageno != AsmStage::numstages() - 1) {
258 merge.mpr_bus_dep.mpr_bus_dep_ingress = this[1].stage_dep[INGRESS] != MATCH_DEP;
259 merge.mpr_bus_dep.mpr_bus_dep_egress = this[1].stage_dep[EGRESS] != MATCH_DEP;
260 }
261
262 merge.mpr_bus_dep.mpr_bus_dep_glob_exec = mpr_bus_dep_glob_exec[INGRESS] |
263 mpr_bus_dep_glob_exec[EGRESS] |
264 mpr_bus_dep_glob_exec[GHOST];
265 merge.mpr_bus_dep.mpr_bus_dep_long_brch = mpr_bus_dep_long_branch[INGRESS] |
266 mpr_bus_dep_long_branch[EGRESS] |
267 mpr_bus_dep_long_branch[GHOST];
268
269 merge.mpr_long_brch_thread = long_branch_thread[EGRESS];
270 if (auto conflict = (long_branch_thread[INGRESS] | long_branch_thread[GHOST]) &
271 long_branch_thread[EGRESS]) {
272 // Should probably check this earlier, but there's not a good place to do it.
273 for (auto tag : bitvec(conflict)) {
274 error(long_branch_use[tag]->lineno,
275 "Need one-stage turnaround before reusing "
276 "long_branch tag %d in a different thread",
277 tag);
278 }
279 }
280
281 bitvec in_use = match_use[INGRESS] | action_use[INGRESS] | action_set[INGRESS];
282 bitvec eg_use = match_use[EGRESS] | action_use[EGRESS] | action_set[EGRESS];
283 /* FIXME -- if the regs are live across a stage (even if not used in that stage) they
284 * need to be set in the thread registers. For now we just assume if they are used
285 * anywhere, they need to be marked as live */
286 in_use |= Phv::use(INGRESS);
287 eg_use |= Phv::use(EGRESS);
288 static const int phv_use_transpose[2][14] = {
289 {0, 1, 2, 3, 8, 9, 10, 11, 16, 17, 18, 19, 20, 21},
290 {4, 5, 6, 7, 12, 13, 14, 15, 22, 23, 24, 25, 26, 27}};
291 // FIXME -- this code depends on the Phv::Register uids matching the
292 // FIXME -- mau encoding of phv containers. (FIXME-PHV)
293 for (int i = 0; i < 2; i++) {
294 for (int j = 0; j < 14; j++) {
295 regs.dp.phv_ingress_thread[i][j] = regs.dp.phv_ingress_thread_imem[i][j] =
296 in_use.getrange(10 * phv_use_transpose[i][j], 10);
297 regs.dp.phv_egress_thread[i][j] = regs.dp.phv_egress_thread_imem[i][j] =
298 eg_use.getrange(10 * phv_use_transpose[i][j], 10);
299 }
300 }
301
302 /* Things following are for debug/bringup only : not for normal flows */
303
304 if (options.disable_power_gating) {
305 disable_jbay_power_gating(regs);
306 }
307
308 write_teop_regs(regs);
309}
310
311void AlwaysRunTable::write_regs(Target::JBay::mau_regs &regs) {
312 if (gress == EGRESS)
313 regs.dp.imem_word_read_override.imem_word_read_override_egress = 1;
314 else
315 regs.dp.imem_word_read_override.imem_word_read_override_ingress = 1;
316 actions->write_regs(regs, this);
317}
Definition checked_array.h:34
Definition backends/tofino/bf-asm/json.h:300
Definition backends/tofino/bf-asm/json.h:144
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 ubits.h:42