1 // See LICENSE for license details.
3 /* state-machine for Simple-V "hardware-macro-loop-unroller".
5 see insn_template_sv.txt for design details
12 #include "sv_insn_redirect.h"
14 #ifdef INSN_TYPE_BRANCH
15 #define set_pc(x) insn.setpc(xlen, vlen, npc, x, \
16 *dest_offs, target_reg, zeroingtarg, invtarg);
18 #define set_pc _set_pc
21 reg_t
FN(processor_t
* p
, insn_t s_insn
, reg_t pc
)
23 return p
->s
.FN(p
, s_insn
, pc
);
27 #define sv_enabled false
28 // not going to make any difference...
29 #define DEST_PREDINT 1
31 #define PRED_ARGS dest_pred,dest_pred,dest_pred,dest_pred,dest_pred,&dest_pred
32 #define OFFS_ARGS dest_offs,dest_offs,dest_offs,dest_offs,dest_offs,dest_offs
34 #define sv_enabled true
37 reg_t
sv_proc_t::FN(processor_t
* p
, insn_t s_insn
, reg_t pc
)
40 reg_t npc
= _sext_xlen(pc
+ insn_length(INSNCODE
));
41 // messy way to do it: insn_t is used elsewhere in a union,
42 // so cannot create virtual functions.
43 // a workaround is to grab the bits from the insn_t
44 // and create an sv-variant. also an opportunity to pass
45 // in a stack of other things that are needed.
46 insn_bits_t bits
= s_insn
.bits();
48 if (p
->get_state()->prv
== 0) { // XXX HACK - disable in supervisor mode
49 vlen
= p
->get_state()->sv().vl
;
51 // need to know if register is used as float or int.
52 // REGS_PATTERN is generated by id_regs.py (per opcode)
53 unsigned int floatintmap
= REGS_PATTERN
;
55 reg_t dest_pred
= ~0x0;
56 bool dest_pset
= false;
57 int *dest_offs
= &(p
->get_state()->sv().destoffs
);
59 #ifdef INSN_CATEGORY_TWINPREDICATION
61 reg_t src_pred
= ~0x0;
62 bool src_pset
= false;
63 int *src_offs
= &(p
->get_state()->sv().srcoffs
);
64 bool zeroingsrc
= false;
66 #ifdef INSN_TYPE_BRANCH
67 reg_t target_pred
= ~0x0;
68 bool zeroingtarg
= false;
71 sv_insn_t
insn(p
, sv_enabled
, bits
, floatintmap
, xlen
,
72 INSN_SRC_FLEN
, INSN_DEST_FLEN
,
74 #ifdef INSN_TYPE_SIGNED
80 p
->s
.set_insn(&insn
, xlen
);
84 #ifdef INSN_TYPE_BRANCH
85 #ifdef INSN_TYPE_C_BRANCH
86 sv_pred_entry
*r
= insn
.get_predentry(0, true); // yes, really taken from x0
88 sv_pred_entry
*r
= insn
.get_predentry(s_insn
.rs2(), true);
90 reg_t _target_reg
= 0;
91 reg_t
*target_reg
= NULL
;
93 reg_spec_t sp
= {0, NULL
};
96 fprintf(stderr
, "pre-ex reg %s %x %ld rd %ld rs1 %ld rs2 %ld vlen %d\n",
97 xstr(INSN
), INSNCODE
, p
->get_state()->prv
,
98 s_insn
.rd(), s_insn
.rs1(), s_insn
.rs2(),
100 #ifdef INSN_TYPE_C_STACK_LD
101 sp
= insn
._remap(X_SP
, true, src_offs
);
103 #ifdef INSN_TYPE_C_STACK_ST
104 sp
= insn
._remap(X_SP
, true, dest_offs
);
106 #ifdef INSN_TYPE_BRANCH
107 // all branch ops are rs1, rs2. take target (dest) predicate from rs2.
110 _target_reg
= r
->regidx
;
111 target_reg
= &_target_reg
;
112 #ifdef INSN_TYPE_C_BRANCH
113 target_pred
= insn
.predicate(0, true, zeroingtarg
, invtarg
);
115 target_pred
= insn
.predicate(s_insn
.rs2(), true, zeroingtarg
, invtarg
);
117 fprintf(stderr
, "branch pred reg %ld pred %lx\n",
118 _target_reg
, target_pred
);
121 #ifdef INSN_CATEGORY_TWINPREDICATION
122 #ifdef INSN_TYPE_C_STACK_LD
125 src_preg
= s_insn
.SRC_REG();
127 src_pred
= insn
.predicate(src_preg
, SRC_PREDINT
, zeroingsrc
);
130 #ifdef INSN_TYPE_C_STACK_ST
133 // use the ORIGINAL, i.e. NON-REDIRECTED, register here
134 dest_preg
= s_insn
.DEST_REG();
136 dest_pred
= insn
.predicate(dest_preg
, DEST_PREDINT
, zeroing
);
139 #if 0 // useful test at one point...
140 if (insn
.sv_check_reg(true, 15))
142 fprintf(stderr
, "reg %s %x rd %ld rs1 %ld rs2 %ld vlen %d\n",
143 xstr(INSN
), INSNCODE
, s_insn
.rd(), s_insn
.rs1(), s_insn
.rs2(),
147 // if vectorop is set, one of the regs is not a scalar,
148 // so we must read the VL CSR and do a loop
151 vlen
= 1; // minimum of one loop
153 for (int voffs
=0; voffs
< vlen
; voffs
++)
155 insn
.reset_vloop_check();
157 fprintf(stderr
, "pre twin reg %s src %d dest %d pred %lx %lx vlen %d\n",
158 xstr(INSN
), *src_offs
, *dest_offs
, src_pred
, dest_pred
, vlen
);
161 fprintf(stderr
, "pre twin reg %s src %lx dest %d pred %lx %lx\n",
162 xstr(INSN
), _target_reg
, *dest_offs
, target_pred
, dest_pred
);
164 #ifdef INSN_CATEGORY_TWINPREDICATION
165 if (*src_offs
>= vlen
) {
168 if (*dest_offs
>= vlen
) {
172 fprintf(stderr
, "pre twin reg %s src %d dest %d pred %lx %lx\n",
173 xstr(INSN
), *src_offs
, *dest_offs
, src_pred
, dest_pred
);
177 while ((src_pset
= (src_pred
& (1<<pred_remap(src_preg
, *src_offs
))))
180 if (*src_offs
>= vlen
) {
187 while ((dest_pset
= (dest_pred
& (1<<pred_remap(dest_preg
, *dest_offs
))))
190 if (*dest_offs
>= vlen
) {
195 if (*src_offs
>= vlen
|| *dest_offs
>= vlen
) {
196 break; // end vector loop if either src or dest pred reaches end
200 fprintf(stderr
, "twin reg %s src %d dest %d pred %lx %lx\n",
201 xstr(INSN
), *src_offs
, *dest_offs
, src_pred
, dest_pred
);
205 fprintf(stderr
, "pre %s %x vloop %d %d %d" \
206 "vlen %d stop %d pred %lx rdv %lx v %ld rvc2 %ld sp %lx\n",
207 xstr(INSN
), INSNCODE
, voffs
, *src_offs
, *dest_offs
,
208 vlen
, insn
.stop_vloop(),
209 dest_pred
& (1<<voffs
), READ_REG(insn
._rvc_rs2()),
210 insn
._rvc_rs2().reg
, insn
.rvc_lwsp_imm(), READ_REG(sp
));
213 fprintf(stderr
, "pre %s %x vloop %d %d %d" \
214 "vlen %d stop %d pred %lx rdv %lx rd %ld rvc2 %ld sp %lx\n",
215 xstr(INSN
), INSNCODE
, voffs
, *src_offs
, *dest_offs
,
216 vlen
, insn
.stop_vloop(),
217 dest_pred
& (1<<voffs
), READ_REG(insn
._rd()),
218 insn
._rd().reg
, insn
.rvc_lwsp_imm(), READ_REG(sp
));
221 fprintf(stderr
, "pre %s %x vloop %d %ld %d" \
222 "vlen %d stop %d pred %lx rdv %lx rvc_rs1 %ld\n",
223 xstr(INSN
), INSNCODE
, voffs
, _target_reg
, *dest_offs
,
224 vlen
, insn
.stop_vloop(),
225 dest_pred
& (1<<voffs
), READ_REG(insn
._rvc_rs1s()),
226 insn
._rvc_rs1s().reg
);
229 fprintf(stderr
, "pre %s %x vloop %d %d %d" \
230 "vlen %d stop %d pred %lx rdv %lx rvc_rs1 %ld\n",
231 xstr(INSN
), INSNCODE
, voffs
, *src_offs
, *dest_offs
,
232 vlen
, insn
.stop_vloop(),
233 dest_pred
& (1<<voffs
), READ_REG(insn
._rs1()),
238 #ifndef INSN_TYPE_C_STACK_ST // XXX TODO: stack-based DEST_REG
239 reg_spec_t rdr
= insn
._DEST_REG();
240 bool dest_predicated
= (dest_pred
& (1<<*dest_offs
)) != 0;
242 fprintf(stderr
, "post %s %x doffs %lx dp %x zeroing %d tozero %d" \
244 xstr(INSN
), INSNCODE
,
245 dest_pred
, *dest_offs
, zeroing
, dest_predicated
,
246 rdr
.reg
, READ_REG(rdr
));
248 // don't check inversion here as dest_pred has already been inverted
249 if (zeroing
&& (!dest_predicated
))
251 // insn._rd() would be predicated: have to use insn._rd() here
254 else if (!zeroing
&& dest_predicated
&& !rdr
.isvec
)
256 // zeroing not set, answer was stored, and it's a scalar operand.
257 // time to exit the loop.
264 #if defined(USING_REG_RD)
265 fprintf(stderr
, "reg %s %x vloop %d vlen %d stop %d pred %lx rd%lx\n",
266 xstr(INSN
), INSNCODE
, voffs
, vlen
, insn
.stop_vloop(),
267 dest_pred
& (1<<voffs
), READ_REG(insn
._rd()));
269 #if defined(USING_REG_FRD)
270 fprintf(stderr
, "reg %s %x vloop %d vlen %d stop %d pred %lx rd%g\n",
271 xstr(INSN
), INSNCODE
, voffs
, vlen
, insn
.stop_vloop(),
272 dest_pred
& (1<<voffs
),
273 (double)(READ_FREG(insn
._rd())).v
[0]);
276 if (insn
.stop_vloop())
280 #ifdef INSN_CATEGORY_TWINPREDICATION
285 #ifdef INSN_TYPE_BRANCH
286 // ok, at the end of the loop, if the predicates are equal,
287 // we're good to branch. use the saved address (to avoid
288 // calculating the BRANCH_TARGET macro again)
289 if (r
->active
) // only when predication is set
291 uint64_t mask
= (1<<vlen
) - 1;
292 if (insn
.get_if_one_reg_vectorised() &&
293 (insn
.get_saved_branch_rd() & mask
) == (target_pred
& mask
))
295 fprintf(stderr
, "vector branch ACTIVE\n");
296 _set_pc(insn
.get_saved_branch_addr());
300 // ok at the **END** of the looping we set the (ref'd) dest_offs and
301 // src_offs to zero. this allows any exceptions that are thrown
302 // to leave dest_offs and src_offs as they are, such that when
303 // the instruction is re-run it continues from where things left off.
305 #ifdef INSN_CATEGORY_TWINPREDICATION
309 trace_opcode(p
, INSNCODE
, insn
);