add sv predication function
[riscv-isa-sim.git] / riscv / sv.cc
1 #include "sv.h"
2 #include "sv_decode.h"
3
4 sv_reg_csr_entry sv_csrs[SV_CSR_SZ];
5 sv_reg_entry sv_int_tb[NXPR];
6 sv_reg_entry sv_fp_tb[NFPR];
7 sv_pred_csr_entry sv_pred_csrs[SV_CSR_SZ];
8 sv_pred_entry sv_pred_int_tb[NXPR];
9 sv_pred_entry sv_pred_fp_tb[NFPR];
10
11 bool sv_check_reg(bool intreg, uint64_t reg)
12 {
13 sv_reg_entry *r;
14 if (intreg)
15 {
16 r = &sv_int_tb[reg];
17 }
18 else
19 {
20 r = &sv_fp_tb[reg];
21 }
22 if (r->elwidth != 0)
23 {
24 // XXX raise exception
25 }
26 if (r->active && r->isvec)
27 {
28 return true;
29 }
30 return false;
31 }
32
33 /* this is the "remap" function. note that registers can STILL BE REDIRECTED
34 * yet NOT BE MARKED AS A VECTOR.
35 *
36 * reg 5 -> active=false, regidx=XX, isvec=XX -> returns 5
37 * reg 5 -> active=true , regidx=35, isvec=false -> returns 35
38 * reg 5 -> active=true , regidx=35, isvec=true -> returns 35 *PLUS LOOP*
39 *
40 * so it is possible for example to use the remap system for C instructions
41 * to get access to the *full* range of registers x0..x63 (yes 63 because
42 * SV doubles both the int and fp regfile sizes), by setting
43 * "active=true, isvec=false" for any of x8..x15
44 *
45 * where "active=true, isvec=true" this is the "expected" behaviour
46 * of SV. it's "supposed" to "just" be a vectorisation API. it isn't:
47 * it's quite a bit more.
48 */
49 uint64_t sv_insn_t::remap(uint64_t reg, bool intreg, int &voffs)
50 {
51 // okaay so first determine which map to use. intreg is passed
52 // in (ultimately) from id_regs.py's examination of the use of
53 // FRS1/RS1, WRITE_FRD/WRITE_RD, which in turn gets passed
54 // in from sv_insn_t::fimap...
55 sv_reg_entry *r;
56 if (intreg)
57 {
58 r = &sv_int_tb[reg];
59 }
60 else
61 {
62 r = &sv_fp_tb[reg];
63 }
64 // next we check if this entry is active. if not, the register
65 // is not being "redirected", so just return the actual reg.
66 if (!r->active)
67 {
68 return reg; // not active: return as-is
69 }
70
71 // next we go through the lookup table. *THIS* is why the
72 // sv_reg_entry table is 32 entries (5-bit) *NOT* 6 bits
73 // the *KEY* (reg) is 5-bit, the *VALUE* (actual target reg) is 6-bit
74 // XXX TODO: must actually double NXPR and NXFR in processor.h to cope!!
75 reg = r->regidx;
76
77 // now we determine if this is a scalar/vector: if it's scalar
78 // we return the re-mapped register...
79 if (!r->isvec) // scalar
80 {
81 return reg; // ... remapped at this point...
82 }
83
84 // aaand now, as it's a "vector", FINALLY we can add on the loop-offset
85 // which was passed in to the sv_insn_t constructor (by reference)
86 // and, at last, we have "parallelism" a la contiguous registers.
87 reg += voffs; // wheww :)
88
89 // however... before returning, we increment the loop-offset for
90 // this particular register, so that on the next loop the next
91 // contiguous register will be used.
92 voffs += 1;
93 return reg;
94 }
95
96 /* gets the predication value (if active). returns all-1s if not active
97 * also returns whether zeroing is enabled/disabled for this register.
98 *
99 * uses the same sort of lookup logic as remap:
100 *
101 * - first thing to note is, there is one CSR table for FP and one for INT
102 * (so, FP regs can be predicated separately from INT ones)
103 * - redirection occurs if the CSR entry for the register is "active".
104 * - inversion of the predication can be set (so it's possible to have
105 * the same actual register value be unchanged yet be referred to by
106 * *TWO* redirections, one with inversion, one with not).
107 *
108 * note that this function *actually* returns the value of the (integer)
109 * register file, hence why processor_t has to be passed in
110 *
111 * note also that *even scalar* ops will be predicated (i.e. if a register
112 * has been set active=true and isvec=false in sv_int_tb or sv_fp_tb).
113 * the way to ensure that scalar ops are not predicated is: set VLEN=0,
114 * set active=false in sv_int_tb/sv_fp_tb for that register, or switch off
115 * the predication for that register (sv_pred_int_tb/sv_pred_fb_tb).
116 *
117 * note also that the hard limit on SV maximum vector length is actually
118 * down to the number of bits in the predication i.e. the bitwidth of integer
119 * registers (i.e. XLEN bits).
120 */
121 reg_t sv_insn_t::predicate(processor_t *p, uint64_t reg,
122 bool intreg, bool &zeroing)
123 {
124 sv_pred_entry *r;
125 if (intreg)
126 {
127 r = &sv_pred_int_tb[reg];
128 }
129 else
130 {
131 r = &sv_pred_fp_tb[reg];
132 }
133 if (!r->active)
134 {
135 return ~0x0; // not active: return all-1s (unconditional "on")
136 }
137 zeroing = r->zero;
138 reg = r->regidx;
139 reg_t predicate = READ_REG(reg); // macros go through processor_t state
140 if (r->inv)
141 {
142 return ~predicate;
143 }
144 return predicate;
145 }