22struct DivMod :
public AluOP {
23 struct Decode :
public AluOP::Decode {
24 Decode(
const char *name, target_t targ,
int opc) : AluOP::Decode(name, targ, opc) {}
26 const VECTOR(
value_t) & op)
const override {
27 auto *rv =
new DivMod(
this, op[0].lineno);
28 if (op.size != 3) error(op[0].lineno,
"divmod must have exactly 2 operands");
29 if (op.size > 1) rv->srca = operand(tbl, act, op[1]);
30 if (op.size > 2) rv->srcb = operand(tbl, act, op[2]);
36 DivMod(
const Decode *op,
int l) : AluOP(op, l) {}
39 tbl->stage->table_use[timing_thread(tbl->gress)] |= Stage::USE_STATEFUL_DIVIDE;
40 BUG_CHECK(tbl->to<StatefulTable>(),
"stateful instruction on non-stateful table?");
41 tbl->to<StatefulTable>()->divmod_used =
true;
42 return AluOP::pass1(tbl, act);
44 FOR_ALL_REGISTER_SETS(DECLARE_FORWARD_VIRTUAL_INSTRUCTION_WRITE_REGS)
54 AluOP::write_regs(regs, tbl, act);
55 int logical_home_row = tbl->layout[0].row;
56 auto &meter_group = regs.rams.map_alu.meter_group[logical_home_row / 4U];
57 auto &salu_instr_common = meter_group.stateful.salu_instr_common[act->code];
58 salu_instr_common.salu_divide_enable |= 1;
61struct MinMax :
public SaluInstruction {
65 Decode(
const char *name, target_t targ,
int op)
68 const VECTOR(
value_t) & op)
const override;
71 operand mask, postmod;
73 boost::optional<unsigned> constval = boost::none;
74 MinMax(
const Decode *op,
int l) : SaluInstruction(l), opc(op) {}
75 std::string name()
override {
return opc->name; };
76 Instruction *pass1(Table *tbl, Table::Actions::Action *)
override;
77 void pass2(Table *tbl, Table::Actions::Action *)
override;
78 bool salu_alu()
const override {
return true; }
79 bool equiv(Instruction *a_)
override {
80 if (
auto *a =
dynamic_cast<MinMax *
>(a_))
81 return opc == a->opc && phv == a->phv && mask == a->mask && postmod == a->postmod;
84 bool phvRead(std::function<
void(const ::Phv::Slice &sl)>)
override {
return phv; }
85 void dbprint(std::ostream &out)
const override {
86 out <<
"INSTR: " << opc->name << (phv ?
"phv, " :
"mem, ") << mask;
87 if (postmod) out <<
", " << postmod;
89 FOR_ALL_REGISTER_SETS(DECLARE_FORWARD_VIRTUAL_INSTRUCTION_WRITE_REGS)
92MinMax::Decode opMIN8(
"min8", JBAY, 0), opMAX8(
"max8", JBAY, 1), opMIN16(
"min16", JBAY, 2),
93 opMAX16(
"max16", JBAY, 3);
96 const VECTOR(
value_t) & op)
const {
97 auto *rv =
new MinMax(
this, op[0].lineno);
101 else if (op[1] !=
"mem")
102 error(op[1].lineno,
"%s source must be 'mem' or 'phv'", op[0].s);
103 rv->mask = operand(tbl, act, op[2]);
104 if (!rv->mask.to<operand::Phv>() && !rv->mask.to<operand::Const>())
105 error(op[1].lineno,
"%s mask must be constant or from phv or hash_dist", op[0].s);
107 error(op[0].lineno,
"%s must have a single mask operand", op[0].s);
110 rv->postmod = operand(tbl, act, op[3]);
111 }
else if (op.size > 4) {
112 error(op[0].lineno,
"too many operands for %s", op[0].s);
117Instruction *MinMax::pass1(Table *tbl_, Table::Actions::Action *act) {
118 auto tbl =
dynamic_cast<StatefulTable *
>(tbl_);
119 BUG_CHECK(tbl,
"expected stateful table");
120 int mask_size = (opc->opcode & 2) ? 8 : 16;
121 constval = boost::none;
123 act->minmax_use =
true;
124 if (
auto k = mask.to<operand::Const>()) {
125 if (k->value < 0 || k->value >= (1U << mask_size) || mask.neg)
126 error(k->lineno,
"%s mask value out of range", name().c_str());
127 constval = k->value & ((1U << mask_size) - 1);
128 }
else if (
auto p = mask.to<operand::Phv>()) {
129 if (p->phv_index(tbl))
130 error(lineno,
"%s phv mask must come from the lower half input", name().c_str());
132 error(mask->lineno,
"%s invalid mask", name().c_str());
135 if (
auto k = postmod.to<operand::Const>()) {
137 k->value = -k->value;
138 postmod.neg = !postmod.neg;
140 if (k->value > 255)
error(lineno,
"%s post mod too large", name().c_str());
141 constval = constval.get_value_or(0) | (k->value & 0xff) << mask_size;
142 }
else if (
auto p = postmod.to<operand::Phv>()) {
143 if (!p->phv_index(tbl))
144 error(lineno,
"%s phv post mod must come from the upper half input",
147 error(postmod->lineno,
"%s invalid post mod", name().c_str());
153 if (constval) tbl->get_const(lineno, *constval);
156void MinMax::pass2(Table *tbl, Table::Actions::Action *act) {
157 if (act->slot_use.intersects(bitvec(ALU2LO, 4)))
158 error(lineno,
"min/max requires all 4 stateful alu slots be unused");
160void MinMax::write_regs(Target::JBay::mau_regs ®s, Table *tbl_, Table::Actions::Action *act) {
161 auto tbl =
dynamic_cast<StatefulTable *
>(tbl_);
162 BUG_CHECK(tbl,
"expected stateful table");
163 int logical_home_row = tbl->layout[0].row;
164 auto &meter_group = regs.rams.map_alu.meter_group[logical_home_row / 4U];
165 auto &salu_instr_common = meter_group.stateful.salu_instr_common[act->code];
166 if (
auto k = mask.to<operand::Const>()) {
167 salu_instr_common.salu_minmax_mask_ctl = 1;
169 salu_instr_common.salu_minmax_mask_ctl = 0;
171 salu_instr_common.salu_minmax_ctl = opc->opcode;
172 salu_instr_common.salu_minmax_enable = 1;
174 if (
auto k = postmod.to<operand::Const>()) {
175 salu_instr_common.salu_minmax_postmod_value_ctl = 0;
177 salu_instr_common.salu_minmax_postmod_value_ctl = 1;
180 salu_instr_common.salu_minmax_postdec_enable = 1;
182 salu_instr_common.salu_minmax_postinc_enable = 1;
185 auto &salu_instr_cmp = meter_group.stateful.salu_instr_cmp_alu[act->code][3];
186 salu_instr_cmp.salu_cmp_regfile_adr = tbl->get_const(lineno, *constval);
189 for (
auto &salu : meter_group.stateful.salu_instr_state_alu[act->code]) {
192 salu.salu_pred = 0xffff;
195void MinMax::write_regs(Target::Tofino::mau_regs &, Table *, Table::Actions::Action *) {
200void AluOP::write_regs(Target::JBay::mau_regs ®s, Table *tbl_, Table::Actions::Action *act) {
202 auto tbl =
dynamic_cast<StatefulTable *
>(tbl_);
203 BUG_CHECK(tbl,
"expected stateful table");
204 int logical_home_row = tbl->layout[0].row;
205 auto &meter_group = regs.rams.map_alu.meter_group[logical_home_row / 4U];
206 auto &salu = meter_group.stateful.salu_instr_state_alu[act->code][slot - ALU2LO];
207 auto &salu_ext = meter_group.stateful.salu_instr2_state_alu[act->code][slot - ALU2LO];
208 auto &salu_instr_common = meter_group.stateful.salu_instr_common[act->code];
209 auto &salu_instr_output_alu = meter_group.stateful.salu_instr_output_alu[act->code];
210 salu.salu_op = opc->opcode & 0xf;
211 salu.salu_arith = opc->opcode >> 4;
212 salu.salu_pred = predication_encode;
213 bool need_flyover = (tbl->format->size >> tbl->is_dual_mode()) > 32;
214 const int alu_const_min = Target::STATEFUL_ALU_CONST_MIN();
215 const int alu_const_max = Target::STATEFUL_ALU_CONST_MAX();
217 if (
auto m = srca.to<operand::Memory>()) {
218 salu.salu_asrc_input = m->field->bit(0) > 0 ? 1 : 0;
220 salu_ext.salu_flyover_src_sel = 1;
221 need_flyover =
false;
223 }
else if (
auto f = srca.to<operand::Phv>()) {
224 salu.salu_asrc_input = f->phv_index(tbl) ? 3 : 2;
226 salu_ext.salu_flyover_src_sel = 1;
227 need_flyover =
false;
229 }
else if (
auto k = srca.to<operand::Const>()) {
230 salu.salu_asrc_input = 4;
231 if (k->value >= alu_const_min && k->value <= alu_const_max) {
232 salu.salu_const_src = k->value & Target::STATEFUL_ALU_CONST_MASK();
233 salu.salu_regfile_const = 0;
235 salu.salu_const_src = tbl->get_const(k->lineno, k->value);
236 salu.salu_regfile_const = 1;
238 }
else if (
auto r = srca.to<operand::Regfile>()) {
239 salu.salu_asrc_input = 4;
240 salu.salu_const_src = r->index;
241 salu.salu_regfile_const = 1;
247 if (
auto m = srcb.to<operand::Memory>()) {
248 salu.salu_bsrc_input = m->field->bit(0) > 0 ? 3 : 2;
250 salu_ext.salu_flyover_src_sel = 0;
251 need_flyover =
false;
253 }
else if (
auto f = srcb.to<operand::Phv>()) {
254 salu.salu_bsrc_input = f->phv_index(tbl) ? 1 : 0;
256 salu_ext.salu_flyover_src_sel = 0;
257 need_flyover =
false;
259 }
else if (
auto m = srcb.to<operand::MathFn>()) {
260 salu_instr_common.salu_alu2_lo_bsrc_math = 1;
261 if (
auto b = m->of.to<operand::Phv>()) {
262 salu_instr_common.salu_alu2_lo_math_src = b->phv_index(tbl);
263 }
else if (
auto b = m->of.to<operand::Memory>()) {
264 salu_instr_common.salu_alu2_lo_math_src = b->field->bit(0) > 0 ? 3 : 2;
266 BUG(
"invalid mathfn operand");
268 }
else if (
auto k = srcb.to<operand::Const>()) {
269 salu.salu_bsrc_input = 4;
270 if (k->value >= alu_const_min && k->value <= alu_const_max) {
271 salu.salu_const_src = k->value & Target::STATEFUL_ALU_CONST_MASK();
272 salu.salu_regfile_const = 0;
274 salu.salu_const_src = tbl->get_const(k->lineno, k->value);
275 salu.salu_regfile_const = 1;
277 }
else if (
auto r = srcb.to<operand::Regfile>()) {
278 salu.salu_bsrc_input = 4;
279 salu.salu_const_src = r->index;
280 salu.salu_regfile_const = 1;
286void AluOP::write_regs(Target::JBay::mau_regs ®s, Table *tbl, Table::Actions::Action *act) {
287 write_regs<Target::JBay::mau_regs>(regs, tbl, act);
291void BitOP::write_regs(Target::JBay::mau_regs ®s, Table *tbl, Table::Actions::Action *act) {
293 int logical_home_row = tbl->layout[0].row;
294 auto &meter_group = regs.rams.map_alu.meter_group[logical_home_row / 4U];
295 auto &salu = meter_group.stateful.salu_instr_state_alu[act->code][slot - ALU2LO];
296 salu.salu_op = opc->opcode & 0xf;
297 salu.salu_pred = predication_encode;
299 salu.salu_asrc_input = 0;
301void BitOP::write_regs(Target::JBay::mau_regs ®s, Table *tbl, Table::Actions::Action *act) {
302 write_regs<Target::JBay::mau_regs>(regs, tbl, act);
305static int sbus_mask(
int alu,
const std::vector<Table::Ref> &tbls) {
307 for (
auto &tbl : tbls) {
308 int bit = tbl->layout[0].row / 4U;
309 if (bit > alu) --bit;
316void CmpOP::write_regs(Target::JBay::mau_regs ®s, Table *tbl_, Table::Actions::Action *act) {
318 auto tbl =
dynamic_cast<StatefulTable *
>(tbl_);
319 BUG_CHECK(tbl,
"expected stateful table");
320 int logical_home_row = tbl->layout[0].row;
321 auto &meter_group = regs.rams.map_alu.meter_group[logical_home_row / 4U];
322 auto &salu = meter_group.stateful.salu_instr_cmp_alu[act->code][slot];
323 auto &salu_instr_common = meter_group.stateful.salu_instr_common[act->code];
325 salu.salu_cmp_asrc_input = srca->field->bit(0) > 0;
326 salu.salu_cmp_asrc_sign = srca_neg;
327 salu.salu_cmp_asrc_enable = 1;
328 if (maska != uint32_t(-1)) {
329 salu.salu_cmp_asrc_mask_enable = 1;
331 if (
auto k =
dynamic_cast<const operand::Const *
>(srcc))
333 else if (
auto r =
dynamic_cast<const operand::Regfile *
>(srcc))
334 cval = tbl->get_const_val(r->index);
335 int64_t min = Target::STATEFUL_CMP_CONST_MIN();
336 int64_t max = Target::STATEFUL_CMP_CONST_MAX();
337 bool maska_outside = (maska < uint32_t(min) && maska > max);
338 bool maska_equal_inside = (uint32_t(cval) != maska && cval >= min && cval <= max);
339 if (!maska_outside && !maska_equal_inside) {
340 salu.salu_cmp_const_src = maska & Target::STATEFUL_CMP_CONST_MASK();
341 salu.salu_cmp_mask_input = 0;
343 salu.salu_cmp_regfile_adr = tbl->get_const(srca->lineno, maska);
344 salu.salu_cmp_mask_input = 1;
349 salu.salu_cmp_bsrc_input = srcb->phv_index(tbl);
350 salu.salu_cmp_bsrc_sign = srcb_neg;
351 salu.salu_cmp_bsrc_enable = 1;
352 if (maskb != uint32_t(-1)) {
355 if (salu.salu_cmp_asrc_mask_enable && salu.salu_cmp_mask_input && maskb != maska)
356 error(lineno,
"inconsistent operand mask %d and %d in salu compare operation",
358 salu.salu_cmp_bsrc_mask_enable = 1;
359 salu.salu_cmp_regfile_adr = tbl->get_const(srcb->lineno, maskb);
363 if (
auto k =
dynamic_cast<const operand::Const *
>(srcc)) {
364 const int cmp_const_min = Target::STATEFUL_CMP_CONST_MIN();
365 const int cmp_const_max = Target::STATEFUL_CMP_CONST_MAX();
366 if (k->value >= cmp_const_min && k->value <= cmp_const_max) {
367 salu.salu_cmp_const_src = k->value & Target::STATEFUL_CMP_CONST_MASK();
368 salu.salu_cmp_regfile_const = 0;
372 if (salu.salu_cmp_asrc_mask_enable && salu.salu_cmp_mask_input &&
373 maska != uint32_t(k->value))
374 error(lineno,
"inconsistent operand mask %d and %d in salu compare operation",
375 maska, uint32_t(k->value));
376 if (salu.salu_cmp_bsrc_mask_enable && salu.salu_cmp_mask_input &&
377 maskb != uint32_t(k->value))
378 error(lineno,
"inconsistent operand mask %d and %d in salu compare operation",
379 maskb, uint32_t(k->value));
380 salu.salu_cmp_regfile_adr = tbl->get_const(srcc->lineno, k->value);
381 salu.salu_cmp_regfile_const = 1;
383 }
else if (
auto r =
dynamic_cast<const operand::Regfile *
>(srcc)) {
384 salu.salu_cmp_regfile_adr = r->index;
385 salu.salu_cmp_regfile_const = 1;
388 salu.salu_cmp_const_src = 0;
389 salu.salu_cmp_regfile_const = 0;
391 salu.salu_cmp_opcode = opc->opcode | (type << 2);
392 auto lmask = sbus_mask(logical_home_row / 4U, tbl->sbus_learn);
393 auto mmask = sbus_mask(logical_home_row / 4U, tbl->sbus_match);
394 salu_instr_common.salu_lmatch_sbus_listen = lmask;
395 salu_instr_common.salu_match_sbus_listen = mmask;
396 salu_instr_common.salu_sbus_in_comb = tbl->sbus_comb;
397 if (lmask || mmask) {
400 salu.salu_cmp_sbus_or = 0;
401 salu.salu_cmp_sbus_and = learn ? 1 : 0;
402 salu.salu_cmp_sbus_invert = learn_not ? 1 : 0;
405void CmpOP::write_regs(Target::JBay::mau_regs ®s, Table *tbl, Table::Actions::Action *act) {
406 write_regs<Target::JBay::mau_regs>(regs, tbl, act);
410void TMatchOP::write_regs(Target::JBay::mau_regs ®s, Table *tbl_, Table::Actions::Action *act) {
412 auto tbl =
dynamic_cast<StatefulTable *
>(tbl_);
413 BUG_CHECK(tbl,
"expected stateful table");
414 int logical_home_row = tbl->layout[0].row;
415 auto &meter_group = regs.rams.map_alu.meter_group[logical_home_row / 4U];
416 auto &salu = meter_group.stateful.salu_instr_cmp_alu[act->code][slot];
417 auto &salu_tmatch = meter_group.stateful.salu_instr_tmatch_alu[act->code][slot];
418 auto &salu_instr_common = meter_group.stateful.salu_instr_common[act->code];
419 salu.salu_cmp_tmatch_enable = 1;
420 salu.salu_cmp_asrc_enable = 1;
421 salu.salu_cmp_bsrc_enable = 1;
422 meter_group.stateful.tmatch_mask[slot][0] = ~mask & 0xffffffffU;
423 meter_group.stateful.tmatch_mask[slot][1] = ~mask >> 32;
424 salu.salu_cmp_opcode = 2;
425 salu.salu_cmp_asrc_input = srca->field->bit(0) > 0;
426 salu.salu_cmp_bsrc_input = srcb->phv_index(tbl);
427 if (
auto lmask = sbus_mask(logical_home_row / 4U, tbl->sbus_learn))
428 salu_instr_common.salu_lmatch_sbus_listen = lmask;
429 if (
auto mmask = sbus_mask(logical_home_row / 4U, tbl->sbus_match))
430 salu_instr_common.salu_match_sbus_listen = mmask;
431 salu.salu_cmp_sbus_or = 0;
432 salu.salu_cmp_sbus_and = learn ? 1 : 0;
433 salu.salu_cmp_sbus_invert = learn_not ? 1 : 0;
435 salu_tmatch.salu_tmatch_vld_ctl = 1;
439void TMatchOP::write_regs(Target::JBay::mau_regs ®s, Table *tbl, Table::Actions::Action *act) {
440 write_regs<Target::JBay::mau_regs>(regs, tbl, act);
443void OutOP::decode_output_mux(Target::JBay, Table *tbl, value_t &op) {
444 static const std::map<std::string, int> ops_mux_lookup = {
445 {
"mem_hi", 1}, {
"mem_lo", 0}, {
"memory_hi", 1}, {
"memory_lo", 0}, {
"phv_hi", 3},
446 {
"phv_lo", 2}, {
"alu_hi", 5}, {
"alu_lo", 4}, {
"minmax_index", 5}, {
"minmax_post", 4},
447 {
"predicate", 6}, {
"address", 7}, {
"div", 8}, {
"mod", 9}, {
"minmax", 10}};
448 if (op.type == tCMD && ops_mux_lookup.count(op[0].s))
449 output_mux = ops_mux_lookup.at(op[0].s);
450 else if (op.type == tSTR && ops_mux_lookup.count(op.s))
451 output_mux = ops_mux_lookup.at(op.s);
455 int tmp = output_mux;
456 if (
auto *phv = src.to<operand::Phv>())
457 output_mux = 2 + phv->phv_index(tbl->to<StatefulTable>());
458 else if (
auto *mem = src.to<operand::Memory>())
459 output_mux = mem->field->bit(0) > 0 ? 1 : 0;
460 BUG_CHECK(tmp < 0 || tmp == output_mux,
"inconsistent output mux decode");
463int OutOP::decode_output_option(Target::JBay, value_t &op) {
464 if (op ==
"lmatch") {
467 lmatch_pred = decode_predicate(op[1]);
469 lmatch_pred = STATEFUL_PREDICATION_ENCODE_UNCOND;
477void OutOP::write_regs(Target::JBay::mau_regs ®s, Table *tbl_, Table::Actions::Action *act) {
479 auto tbl =
dynamic_cast<StatefulTable *
>(tbl_);
480 BUG_CHECK(tbl,
"expected stateful table");
481 int logical_home_row = tbl->layout[0].row;
482 auto &meter_group = regs.rams.map_alu.meter_group[logical_home_row / 4U];
483 auto &salu = meter_group.stateful.salu_instr_output_alu[act->code][slot - ALUOUT0];
484 if (predication_encode) {
485 salu.salu_output_cmpfn = predication_encode;
487 salu.salu_output_cmpfn = STATEFUL_PREDICATION_ENCODE_UNCOND;
489 salu.salu_output_asrc = output_mux;
490 if ((salu.salu_lmatch_adr_bit_enable = lmatch))
491 meter_group.stateful.salu_mathtable[0] = lmatch_pred;
492 if (output_mux == STATEFUL_PREDICATION_OUTPUT)
493 meter_group.stateful.stateful_ctl.salu_output_pred_sel = slot - ALUOUT0;
495void OutOP::write_regs(Target::JBay::mau_regs ®s, Table *tbl, Table::Actions::Action *act) {
496 write_regs<Target::JBay::mau_regs>(regs, tbl, act);
void error(const char *format, Args &&...args)
Report an error with the given message.
Definition lib/error.h:58
Definition jbay/salu_inst.cpp:23
Definition instruction.h:53
Definition instruction.h:26
Definition jbay/salu_inst.cpp:62
Definition asm-types.h:114