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