add comment
[riscv-isa-sim.git] / riscv / insn_template_sv.cc
1 // See LICENSE for license details.
2
3 /* state-machine for Simple-V "hardware-macro-loop-unroller".
4
5 see insn_template_sv.txt for design details
6 */
7
8 #define xstr(s) str(s)
9 #define str(s) #s
10
11 #include "sv.h"
12 #include "sv_insn_redirect.h"
13
14 #ifdef INSN_TYPE_BRANCH
15 #define set_pc(x) insn.setpc(xlen, vlen, npc, x, \
16 *dest_offs, target_reg, zeroingtarg, invtarg);
17 #else
18 #define set_pc _set_pc
19 #endif
20
21 reg_t FN(processor_t* p, insn_t s_insn, reg_t pc)
22 {
23 return p->s.FN(p, s_insn, pc);
24 }
25
26 #ifdef USING_NOREGS
27 #define sv_enabled false
28 // not going to make any difference...
29 #define DEST_PREDINT 1
30 #define SRC_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
33 #else
34 #define sv_enabled true
35 #endif
36
37 reg_t sv_proc_t::FN(processor_t* p, insn_t s_insn, reg_t pc)
38 {
39 int xlen = ISASZ;
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();
47 int vlen = 0;
48 if (p->get_state()->prv == 0) { // XXX HACK - disable in supervisor mode
49 vlen = p->get_state()->sv().vl;
50 }
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;
54 reg_t dest_preg = 0;
55 reg_t dest_pred = ~0x0;
56 bool dest_pset = false;
57 int *dest_offs = &(p->get_state()->sv().destoffs);
58 bool zeroing = false;
59 #ifdef INSN_CATEGORY_TWINPREDICATION
60 reg_t src_preg = 0;
61 reg_t src_pred = ~0x0;
62 bool src_pset = false;
63 int *src_offs = &(p->get_state()->sv().srcoffs);
64 bool zeroingsrc = false;
65 #endif
66 #ifdef INSN_TYPE_BRANCH
67 reg_t target_pred = ~0x0;
68 bool zeroingtarg = false;
69 bool invtarg = false;
70 #endif
71 sv_insn_t insn(p, sv_enabled, bits, floatintmap, xlen,
72 INSN_SRC_FLEN, INSN_DEST_FLEN,
73 PRED_ARGS, OFFS_ARGS,
74 #ifdef INSN_TYPE_SIGNED
75 true
76 #else
77 false
78 #endif
79 );
80 p->s.set_insn(&insn, xlen);
81 #ifdef USING_NOREGS
82 #include INCLUDEFILE
83 #else
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
87 #else
88 sv_pred_entry *r = insn.get_predentry(s_insn.rs2(), true);
89 #endif
90 reg_t _target_reg = 0;
91 reg_t *target_reg = NULL;
92 #endif
93 reg_spec_t sp = {0, NULL};
94 if (vlen > 0)
95 {
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(),
99 vlen);
100 #ifdef INSN_TYPE_C_STACK_LD
101 sp = insn._remap(X_SP, true, src_offs);
102 #endif
103 #ifdef INSN_TYPE_C_STACK_ST
104 sp = insn._remap(X_SP, true, dest_offs);
105 #endif
106 #ifdef INSN_TYPE_BRANCH
107 // all branch ops are rs1, rs2. take target (dest) predicate from rs2.
108 if (r->active)
109 {
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);
114 #else
115 target_pred = insn.predicate(s_insn.rs2(), true, zeroingtarg, invtarg);
116 #endif
117 fprintf(stderr, "branch pred reg %ld pred %lx\n",
118 _target_reg, target_pred);
119 }
120 #endif
121 #ifdef INSN_CATEGORY_TWINPREDICATION
122 #ifdef INSN_TYPE_C_STACK_LD
123 src_preg = sp.reg;
124 #else
125 src_preg = s_insn.SRC_REG();
126 #endif
127 src_pred = insn.predicate(src_preg, SRC_PREDINT, zeroingsrc);
128 #endif
129 #ifdef DEST_PREDINT
130 #ifdef INSN_TYPE_C_STACK_ST
131 dest_preg = sp.reg;
132 #else
133 // use the ORIGINAL, i.e. NON-REDIRECTED, register here
134 dest_preg = s_insn.DEST_REG();
135 #endif
136 dest_pred = insn.predicate(dest_preg, DEST_PREDINT, zeroing);
137 #endif
138 }
139 #if 0 // useful test at one point...
140 if (insn.sv_check_reg(true, 15))
141 {
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(),
144 vlen);
145 }
146 #endif
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
149 if (vlen == 0)
150 {
151 vlen = 1; // minimum of one loop
152 }
153 for (int voffs=0; voffs < vlen; voffs++)
154 {
155 insn.reset_vloop_check();
156 #ifdef INSN_C_MV
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);
159 #endif
160 #ifdef INSN_C_BEQZ
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);
163 #endif
164 #ifdef INSN_CATEGORY_TWINPREDICATION
165 if (*src_offs >= vlen) {
166 break;
167 }
168 if (*dest_offs >= vlen) {
169 break;
170 }
171 #ifdef INSN_C_SWSP
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);
174 #endif
175 if (!zeroingsrc)
176 {
177 while ((src_pset = (src_pred & (1<<pred_remap(src_preg, *src_offs))))
178 == 0) {
179 *src_offs += 1;
180 if (*src_offs >= vlen) {
181 break;
182 }
183 }
184 }
185 if (!zeroing)
186 {
187 while ((dest_pset = (dest_pred & (1<<pred_remap(dest_preg, *dest_offs))))
188 == 0) {
189 *dest_offs += 1;
190 if (*dest_offs >= vlen) {
191 break;
192 }
193 }
194 }
195 if (*src_offs >= vlen || *dest_offs >= vlen) {
196 break; // end vector loop if either src or dest pred reaches end
197 }
198 if (vlen > 1)
199 {
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);
202 }
203 #endif
204 #ifdef INSN_C_SWSP
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));
211 #endif
212 #ifdef INSN_C_LWSP
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));
219 #endif
220 #ifdef INSN_C_BEQZ
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);
227 #endif
228 #ifdef INSN_LD
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()),
234 insn._rs1().reg);
235 #endif
236 #include INCLUDEFILE
237 #ifdef DEST_PREDINT
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;
241 #ifdef INSN_C_MV
242 fprintf(stderr, "post %s %x doffs %lx dp %x zeroing %d tozero %d" \
243 " rdr %d v %x\n",
244 xstr(INSN), INSNCODE,
245 dest_pred, *dest_offs, zeroing, dest_predicated,
246 rdr.reg, READ_REG(rdr));
247 #endif
248 // don't check inversion here as dest_pred has already been inverted
249 if (zeroing && (!dest_predicated))
250 {
251 // insn._rd() would be predicated: have to use insn._rd() here
252 WRITE_REG(rdr, 0);
253 }
254 else if (!zeroing && dest_predicated && !rdr.isvec)
255 {
256 // zeroing not set, answer was stored, and it's a scalar operand.
257 // time to exit the loop.
258 break;
259 }
260 #endif
261 #endif
262 if (vlen > 1)
263 {
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()));
268 #endif
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]);
274 #endif
275 }
276 if (insn.stop_vloop())
277 {
278 break;
279 }
280 #ifdef INSN_CATEGORY_TWINPREDICATION
281 *src_offs += 1;
282 #endif
283 *dest_offs += 1;
284 }
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
290 {
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))
294 {
295 fprintf(stderr, "vector branch ACTIVE\n");
296 _set_pc(insn.get_saved_branch_addr());
297 }
298 }
299 #endif
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.
304 *dest_offs = 0;
305 #ifdef INSN_CATEGORY_TWINPREDICATION
306 *src_offs = 0;
307 #endif
308 #endif
309 trace_opcode(p, INSNCODE, insn);
310 return npc;
311 }
312