add slids
[libreriscv.git] / overloadable_opcodes.mdwn
1 # Overloadable opcodes.
2
3 The overloadable opcode (or xext) proposal allows a non standard extension to use a documented 20 + 3 bit (or 52 + 3 bit on RV64) UUID identifier for an instruction for _software_ to use. At runtime, a cpu translates the UUID to a small implementation defined 12 + 3 bit bit identifier for _hardware_ to use. It also defines a fallback mechanism for the UUID's of instructions the cpu does not recognise.
4
5 Tl;DR see below for a C description of how this is supposed to work.
6
7 It defines a small number N standardised R-type instructions
8 xcmd0, xcmd1, ...xcmd[N-1], preferably in the brownfield opcode space. We usually assume N = 8 (aka log2(8) = 3 in the + 3 above).
9 Each xcmd takes (in rs1) a 12 bit "logical unit" (lun) identifying a (sub)device on the cpu
10 that implements some "extension interface" (xintf) together with some additional data.
11 Extension devices may be implemented in any convenient form, e.g. non standard extensions
12 of the CPU iteself, IP tiles, or closely coupled external devices.
13
14 An xintf is a set of up to N commands with 2 input and 1 output port (i.e. like an
15 R-type instruction), together with a description of the semantics of the commands. Calling
16 e.g. xcmd3 routes its two inputs and one output ports to command 3 on the device determined
17 by the lun bits in rs1. Thus, the N standard xcmd instructions are standard-designated
18 overloadable opcodes, with the non standard semantics of the opcode determined by the lun.
19
20 Portable software, does not use luns directly. Instead, it goes through a level of
21 indirection using a further instruction xext. The xext instruction translates a 20 bit globally
22 unique identifier UUID of an xintf, to the lun of a device on the cpu that implements that xintf.
23 The cpu can do this, because it knows (at manufacturing or boot time) which devices it has, and
24 which xintfs they provide. This includes devices that would be described as non standard extension
25 of the cpu if the designers had used custom opcodes instead of xintf as an interface. If the
26 UUID of the xintf is not recognised at the current privilege level, the xext instruction returns
27 the special lun = 0, causing any xcmd to trap. Minor variations of this scheme (requiring two
28 more instructions xext0 and xextm1) cause xcmd instructions to fallback to always return 0
29 or -1 instead of trapping.
30
31 Remark1: the main difference with a previous "ioctl like proposal" is that UUID translation
32 is stateless and does not use resources. The xext instruction _neither_ initialises a
33 device _nor_ builds global state identified by a cookie. If a device needs initialisation
34 it can do this using xcmds as init and deinit instructions. Likewise, it can hand out
35 cookies (which can include the lun) as a return value .
36
37 Remark2: Implementing devices can respond to an (essentially) arbitrary number of xintfs.
38 Hence, while an xintf is restricted to N commands, an implementing device can have an
39 arbitrary number of commands. Organising related commands in xintfs, helps avoid UUID space
40 pollution, and allows to amortise the (small) cost of UUID to lun translation if related
41 commands are used in combination.
42
43
44 == Description of the instructions ==
45
46 xcmd0 rd, rs1, rs2
47 xcmd1 rd, rs1, rs2
48 ....
49 xcmdN rd, rs1, rs2
50
51 * rs1 contains a 12 bit "logical unit" (lun) together with xlen - 12 bits of additional data.
52 * rs2 is arbitrary
53
54 For e.g xmd3, route the inputs rs1, rs2 and output port rd to command 3 of the (sub)device on the cpu identified by the lun bits of rs1.
55
56 after execution:
57 * rd contains the value that of the output port of the implementing device
58
59 --------
60 xext rd, rs1, rs2
61 xext0 rd, rs1, rs2
62 xextm1 rd, rs1, rs2
63
64
65 * rs1 contains
66 --a UUID of at least 20 bit in bit 12 .. XLEN of rs1 identifying an xintf.
67 --the sequence number of a device at the current privilege level on the cpu implementing the xintf in bit 0..11 .
68 In particular, if bit 0..11 is zero, the default implemententation is requested.
69 * rs2 is arbitrary (but bit XLEN-12 to XLEN -1 is discarded)
70
71 after execution,
72 if the cpu recognises the UUID and device at the current privilege level, rd contains the lun of a device
73 implementing the xintf in bit 0..11, followed by bit 0.. XLEN - 13 of rs2.
74 if the cpu does not recognise the UUID and device it returns the numbers 0 (for xext), 1 (for xext0) or 2 (for xextm1), in particular bit 12.. XLEN are 0.
75
76 ---
77 The net effect is that, when the CPU implements an xintf with UUID 0xABCDE a sequence like
78
79 //fake UUID of an xintf
80 lui rd 0xABCDE
81 xext rd rd rs1
82 xcmd0 rd rd rs2
83
84 acts like a single namespaced instruction cmd0_ABCDE rd rs1 rs2 (with the annoying caveat that the last 12 of rs1 are discarded) The sequence not indivisible but the crucial semantics that you might want to be indivisible is in xcmd0.
85
86 Delegation and UUID is expected to come at a small performance price compared to a "native" instruction. This should, however, be an acceptable tradeoff in many cases. Moreover implementations may opcode-fuse the whole instruction sequence or the first or last two instructions.
87 If several instructions of the same interface are used, one can also use instruction sequences like
88
89 lui t1 0xABCDE //org_tinker_tinker__RocknRoll_uuid
90 xext t1 t1 zero
91 xcmd0 a5, t1, a0 // org_tinker_tinker__RocknRoll__rock(a5, t1, a0)
92 xcmd1 t2, t1, a1 // org_tinker_tinker__RocknRoll__roll(t2, t1, a5)
93 xcmd0 a0, t1, t2 // org_tinker_tinker__RocknRoll__rock(a0, t1, t2)
94
95 If 0xABCDE is an unknown UUID at the current privilege level, the sequence results in a trap just like cmd0_ABCDE rd rs1 rs2 would. The sequence
96
97 //fake UUID of an xintf
98 lui rd 0xABCDE
99 xext0 rd rd rs1
100 xcmd0 rd rd rs2
101
102 acts exactly like the sequence with xext, except that 0 is returned by xcmd0 if the UUID is unknown at the current privilege level. Likewise usage of xextm1 results in -1 being returned. This requires lun = 0 , 1 and 2 to be routed to three mandatory fallback
103 interfaces defined below.
104
105 On the software level, the xintf is just a set of glorified assembler macros
106
107 org.tinker.tinker:RocknRoll{
108 uuid : 0xABCDE
109 rock rd rs1 rs2 : xcmd0 rd rs1 rs2
110 roll rd rs1 rs2 : xcmd1 rd rs1 rs2
111 }
112
113 so that the above sequence can be more clearly written as
114
115 import(org.tinker.tinker:RocknRoll)
116
117 lui rd org.tinker.tinker:RocknRoll:uuid
118 xext rd rd rs1
119 org.tinker.tinker:RocknRoll:rock rd rd rs2
120
121
122 ------
123 The following standard xintfs shall be implemented by the CPU.
124
125 For lun == 0:
126
127 At privilege level user mode, supervisor mode and hypervisor mode
128
129 org.RiscV:Fallback:Trap{
130 uuid: 0
131 trap0 rd rs1 rs2: xcmd0 rd rs1 rs2
132 ...
133 trap[N-1] rd rs1 rs2: xcmd[N-1] rd rs1 rs2
134 }
135
136 each of the xcmd instructions shall trap to one level higher.
137
138 At privilege level machine mode each trap command has unspecified behaviour, but in debug mode
139 should cause an exception to a debug environment.
140
141 For lun == 1, at all privilege levels
142
143 org.RiscV:Fallback:ReturnZero{
144 uuid: 1
145 return_zero0 rd rs1 rs2: xcmd0 rd rs1 rs2
146 ...
147 return_zero[N-1] rd rs1 rs2: xcmd[N-1] rd rs1 rs2
148 }
149
150 each return_zero command shall return 0 in rd.
151
152 For lun == 2, at all privilege levels
153
154 org.RiscV:Fallback:ReturnMinusOne{
155 uuid: 2
156 return_minusone0 rd rs1 rs2: xcmd0 rd rs1 rs2
157 ...
158 return_minusone[N-1] rd rs1 rs2: xcmd[N-1] rd rs1 rs2
159 }
160
161 each return_minusone shall return -1.
162
163 ---
164
165 Remark:
166 Quite possibly even glorified standard assembler macros are overkill and it is
167 easier to just use defines or ordinary macro's with long names. E.g. writing
168
169 #define org_tinker_tinker__RocknRoll__uuid 0xABCDE
170 #define org_tinker_tinker__RocknRoll__rock(rd, rs1, rs2) xcmd0 rd, rs1, rs2
171 #define org_tinker_tinker__RocknRoll__roll(rd, rs1, rs2) xcmd1 rd, rs1, rs2
172
173 allows the same sequence to be written as
174
175 lui rd org_tinker_tinker__RocknRoll__uuid
176 xext rd rs1
177 org_tinker_tinker__RocknRoll__rock(rd, rd, rs2)
178
179 Readability of assembler is no big deal for a compiler, but people are supposed
180 to _document_ the semantics of the interface. In particular specifying the semantics
181 of the xintf in same way as the semantics of the cpu should allow formal verification.
182
183 ==Implications for the RiscV ecosystem ==
184
185 The proposal allows independent groups to define one or more extension
186 interfaces of (slightly crippled) R-type instructions implemented by an
187 extension device. Such an extension device would be an native but non standard
188 extension of the CPU, an IP tile or a closely coupled external chip and would
189 be configured at manufacturing time or bootup of the CPU.
190
191 The 20 bit provided by the UUID of an xintf is much more room than provided by
192 the 2 custom 32 bit, or even 4 custom 64/48 bit opcode spaces. Thus the overloadable
193 opcodes proposal avoids most of the need to put a claim on opcode space,
194 and the associated collisions when combining independent extensions.
195 In this respect it is similar to POSIX ioctls, which (almost) obviate the need for
196 defining new syscalls to control new or nonstandard hardware.
197
198 The expanded flexibility comes at the cost: the standard can specify the
199 semantics of the delegation mechanism and the interfacing with the rest
200 of the cpu, but the actual semantics of the overloaded instructions can
201 only be defined by the designer of the interface. Likewise, a device
202 can be conforming as far as delegation and interaction with the CPU
203 is concerned, but whether the hardware is conforming to the semantics
204 of the interface is outside the scope of spec. Being able to specify
205 that semantics using the methods used for RV itself is clearly very
206 valuable. One impetus for doing that is using it for purposes of its own,
207 effectively freeing opcode space for other purposes. Also, some interfaces
208 may become de facto or de jure standards themselves, necessitating
209 hardware to implement competing interfaces. I.e., facilitating a free
210 for all, may lead to standards proliferation. C'est la vie.
211
212 The only "ISA-collisions" that can still occur are in the 20 bit (~10^6)
213 interface identifier space, with 12 more bits to identify a device on
214 a hart that implements the interface. One suggestion is setting aside
215 2^19 id's that are handed out for a small fee by a central (automated)
216 registration (making sure the space is not just claimed), while the
217 remaining 2^19 are used as a good hash on a long, plausibly globally
218 unique human readable interface name. This gives implementors the choice
219 between a guaranteed private identifier paying a fee, or relying on low
220 probabilities. On RV64 the UUID can also be extended to 52 bits (> 10^15).
221
222
223 ==== Description of the extension as C functions.==
224
225 /* register format of rs1 for xext instructions */
226 typedef struct uuid_device{
227 long dev:12;
228 long uuid: 8*sizeof(long) - 12;
229 } uuid_device_t
230
231 /* register format for rd of xext and rs1 of xcmd instructions, packs lun and data */
232 typedef struct lun_data{
233 long lun:12;
234 long data: 8*sizeof(long) - 12;
235 } lun_data_t
236
237 /* proposed R-type instructions
238 xext rd rs1 rs2
239 xcmd0 rd rs1 rs2
240 xcmd1 rd rs1 rs2
241 ...
242 xcmd7 rd rs1 rs2
243 */
244
245 lun_data_t xext(uuid_dev_t rs1, long rs2);
246 long xcmd0(lun_data_t rs1, long rs2);
247 long xcmd1(lun_data_t rs1, long rs2);
248 ...
249 long xcmd<N>(lun_data_t rs1, long rs2);
250
251 /* hardware interface presented by an implementing device. */
252 typedef
253 long device_fn(unsigned short subdevice_xcmd, lun_data_t rs1, long rs2);
254
255 /* cpu internal datatypes */
256
257 enum privilege = {user = 0b0001, super = 0b0010, hyper = 0b0100, mach = 0b1000};
258
259 /* cpu internal, does what is on the label */
260 static
261 enum privilege cpu__current_privilege_level()
262
263 typedef
264 struct lun{
265 unsigned short id:12
266 } lun_t;
267
268 struct uuid_device_priv2lun{
269 struct{
270 uuid_dev_t uuid_dev;
271 enum privilege reqpriv;
272 };
273 lun_t lun;
274 };
275
276 struct device_subdevice{
277 device_fn* device_addr;
278 unsigned short subdeviceId:12;
279 };
280
281 struct lun_priv2device_subdevice{
282 struct{
283 lun_t lun;
284 enum privilege reqpriv
285 }
286 struct device_subdevice devAddr_subdevId;
287 }
288
289 static
290 struct uuid_device_priv2lun cpu__lun_map[];
291
292 /*
293 map (UUID, device, privilege) to a 12 bit lun,
294 return -1 on unknown (at acces level)
295
296 does associative memory lookup and tests privilege.
297 */
298 static
299 short cpu__lookup_lun(const struct uuid_device_priv2lun* lun_map, uuid_dev_t uuid_dev, enum privilege priv, lun_t on_notfound);
300
301
302 #define org_RiscV__Trap__lun ((lun_t)0)
303 #define org_RiscV__Fallback__ReturnZero__lun ((lun_t)1)
304 #define org_RiscV__Fallback__ReturnMinusOne__lun ((lun_t)2)
305
306 lun_data_t xext(uuid_dev_t rs1, long rs2)
307 {
308 short lun = cpu__lookup_lun(lun_map, rs1, current_privilege_level(), org_RiscV__Fallback__Trap__lun);
309 if(lun < 0)
310 return (lun_data_t){.lun = org_RiscV__Fallback__Trap__lun, .data = 0};
311
312 return (lun_data_t){.lun = lun, .data = rs2 % (1<< (8*sizeof(long) - 12))}
313 }
314
315 lun_data_t xext0(uuid_dev_t rs1, long rs2)
316 {
317 short lun = cpu__lookup_lun(lun_map, rs1, current_privilege_level(), org_RiscV__Fallback__Trap__lun);
318 if(lun < 0)
319 return (lun_data_t){.lun = org_RiscV__Fallback__ReturnZero__lun, .data = 0};
320
321 return (lun_data_t){.lun = lun, .data = rs2 % (1<< (8*sizeof(long) - 12))}
322 }
323
324 lun_data_t xextm1(uuid_dev_t rs1, long rs2)
325 {
326 short lun = cpu__lookup_lun(lun_map, rs1, current_privilege_level(), org_RiscV__Fallback__Trap__lun);
327 if(lun < 0)
328 return (lun_data_t){.lun = org_RiscV__Fallback__ReturnMinusOne__lun, .data = 0};
329
330 return (lun_data_t){.lun = lun, .data = rs2 % (1<< (8*sizeof(long) - 12))}
331 }
332
333
334 struct lun_priv2device_subdevice cpu__device_subdevice_map[];
335
336 /* map (lun, priv) to struct device_subdevice pair.
337 For lun = 0, or unknown (lun, priv) pair, returns (struct device_subdevice){NULL,0}
338 */
339 static
340 device_subdevice_t cpu__lookup_device_subdevice(const struct lun_priv2device_subdevice_map* dev_subdev_map,
341 lun_t lun, enum privileges priv);
342
343
344
345 /* functional description of the delegating xcmd0 .. xcmd7 instructions */
346 template<k = 0..N-1> //pretend this is C
347 long xcmd<k>(lun_data_t rs1, long rs2)
348 {
349 struct device_subdevice dev_subdev = cpu__lookup_device_subdevice(device_subdevice_map, rs1.lun, current_privilege());
350
351 if(dev_subdev.devAddr == NULL)
352 cpu__trap_to(next_privilege);
353
354 return dev_subdev.devAddr(dev_subdev.subdevId | k >> 12 , rs1, rs2);
355 }
356
357 /*Fallback interfaces*/
358 #define org_RiscV__Fallback__ReturnZero__uuid 1
359 #define org_RiscV__Fallback__ReturnMinusOne__uuid 2
360
361 /* fallback device */
362 static
363 long cpu__falback(short subdevice_xcmd, lun_data_t rs1, long rs2)
364 {
365 switch(subdevice_xcmd % (1 << 12) ){
366 case 0 /* org.RiscV:ReturnZero */: return 0;
367 case 1 /* org.RiscV:ReturnMinus1 */: return -1
368 default: trap("hardware configuration error");
369 }
370
371 Example:
372
373 // Fake UUID's
374 #define com_bigbucks__Frobate__uuid 0xABCDE
375 #define org_tinker_tinker__RocknRoll__uuid 0x12345
376 #define org_tinker_tinker__Jazz__uuid 0xBEB0B
377 /*
378 com.bigbucks:Frobate{
379 uuid: com_bigbucks__Frobate__uuid
380 frobate rd rs1 rs2 : cmd0 rd rs1 rs2
381 foo rd rs1 rs2 : cmd1 rd rs1 rs2
382 bar rd rs1 rs2 : cmd1 rd rs1 rs2
383 }
384 */
385 org.tinker.tinker:RocknRoll{
386 uuid: org_tinker_tinker__RocknRoll__uuid
387 rock rd rs1 rs2: cmd0 rd rs1 rs2
388 roll rd rs1 rs2: cmd1 rd rs1 rs2
389 }
390
391 /*
392 Device 1 implements com.bigbucks::Frobate and org.tinker.tinker interfaces, uses
393 a special command for the machine level implementation.
394 */
395
396 long com_bigbucks__device1(short subdevice_xcmd, lun_data_t rs1, long rs2)
397 {
398 switch(subdevice_xcmd) {
399 case 0 | 0 << 12 /* com.bigbucks:Frobate:frobate */ : return device1_frobate(rs1, rs2);
400 case 0 | 7 << 12 /* com.bigbucks:Frobate:frobate */ : return device1_frobate_machine_level(rs1, rs2);
401 case 0 | 1 << 12 /* com.bigbucks:Frobate:foo */ : return device1_foo(rs1, rs2);
402 case 0 | 2 << 12 /* com.bigbucks:Frobate:bar */ : return device1_bar(rs1, rs2);
403 case 1 | 0 << 12 /* org.tinker.tinker:RocknRoll:rock */ : return device1_rock(rs1, rs2);
404 case 1 | 1 << 12 /* org.tinker.tinker:RocknRoll:roll */ : return device1_roll(rs1, rs2);
405 default: trap(“hardware configuration error”);
406 }
407 }
408
409 /*
410 org.tinker.tinker:Jazz{
411 uuid: org_tinker_tinker__Jazz__uuid
412 boogy rd rs1 rs2: cmd0 rd rs1 rs2
413 }
414 */
415
416 /* Device 2 implements Frobate and Jazz interfaces */
417 long org_tinker_tinker__device2(short subdevice_xcmd, lun_data_t rs1, long rs2)
418 {
419 switch(dev_cmd.interfId){
420 case 0 | 0 << 12 /* com.bigbucks:Frobate:frobate */: return device2_frobate(rs1, rs2);
421 case 0 | 1 << 12 /* com.bigbucks:Frobate:foo */ : return device2_foo(rs1, rs2);
422 case 0 | 2 << 12 /* com.bigbucks:Frobate:bar */ : return device2_foo(rs1, rs2);
423 case 1 | 0 << 12 /* org_tinker_tinker:Jazz:boogy */: return device2_boogy(rs1, rs2);
424 default: trap(“hardware configuration error”);
425 }
426 }
427
428 /* cpu assigns luns to the interfaces at different privilege levels on device1 and 2 to luns at manufacturing or boot up time */
429 #define cpu__Device1__Frobate__lun ((lun_t)32)
430 #define cpu__Device1__RocknRoll__lun ((lun_t)33)
431 #define cpu__Device2__Frobate__lun ((lun_t)34)
432 #define cpu__Device2__Jazz__lun ((lun_t)35)
433
434 /* struct uuid_dev2lun_map[] */
435 lun_map = {
436 {{.uuid_devId = {org_RiscV__Fallback__ReturnZero__uuid , 0}, .priv = user}, .lun = org_RiscV__Fallback__ReturnZero__lun},
437 {{.uuid_devId = {org_RiscV__Fallback__ReturnZero__uuid , 0}, .priv = super}, .lun = org_RiscV__Fallback__ReturnZero__lun},
438 {{.uuid_devId = {org_RiscV__Fallback__ReturnZero__uuid , 0}, .priv = hyper}, .lun = org_RiscV__Fallback__ReturnZero__lun},
439 {{.uuid_devId = {org_RiscV__Fallback__ReturnZero__uuid , 0}, .priv = mach} .lun = org_RiscV__Fallback__ReturnZero__lun},
440 {{.uuid_devId = {org_RiscV__Fallback__ReturnMinusOne__uuid, 0}, .priv = user}, .lun = org_RiscV__Fallback__ReturnMinusOne__lun},
441 {{.uuid_devId = {org_RiscV__Fallback__ReturnMinusOne__uuid, 0}, .priv = super}, .lun = org_RiscV__Fallback__ReturnMinusOne__lun},
442 {{.uuid_devId = {org_RiscV__Fallback__ReturnMinusOne__uuid, 0}, .priv = hyper}, .lun = org_RiscV__Fallback__ReturnMinusOne__lun},
443 {{.uuid_devId = {org_RiscV__Fallback__ReturnMinusOne__uuid, 0}, .priv = mach}, .lun = org_RiscV__Fallback__ReturnMinusOne__lun},
444 {{.uuid_devId = {com_bigbucks__Frobate__uuid, 0}, .priv = user} .lun = cpu__Device1__Frobate__lun},
445 {{.uuid_devId = {com_bigbucks__Frobate__uuid, 1}, .priv = super} .lun = cpu__Device1__Frobate__lun},
446 {{.uuid_devId = {com_bigbucks__Frobate__uuid, 1}, .priv = hyper} .lun = cpu__Device1__Frobate__lun},
447 {{.uuid_devId = {com_bigbucks__Frobate__uuid, 1}, .priv = mach} .lun = cpu__Device1__Frobate__lun},
448 {{.uuid_devId = {com_bigbucks__Frobate__uuid, 0}, .priv = super} .lun = cpu__Device2__Frobate__lun},
449 {{.uuid_devId = {com_bigbucks__Frobate__uuid, 0}, .priv = hyper} .lun = cpu__Device2__Frobate__lun},
450 {{.uuid_devId = {com_bigbucks__Frobate__uuid, 0}, .priv = mach} .lun = cpu__Device2__Frobate__lun},
451 {{.uuid_devId = {org_tinker_tinker__RocknRoll__uuid, 0}, .priv = user} .lun = cpu__Device1__RocknRoll__lun},
452 {{.uuid_devId = {org_tinker_tinker__RocknRoll__uuid, 0}, .priv = super} .lun = cpu__Device1__RocknRoll__lun},
453 {{.uuid_devId = {org_tinker_tinker__RocknRoll__uuid, 0}, .priv = hyper} .lun = cpu__Device1__RocknRoll__lun},
454 {{.uuid_devId = {org_tinker_tinker__RocknRoll__uuid, 0}, .priv = super}, .lun = cpu__Device2__Jazz__lun},
455 {{.uuid_devId = {org_tinker_tinker__RocknRoll__uuid, 0}, .priv = hyper}, .lun = cpu__Device2__Jazz__lun},
456 }
457
458 /* cpu maps luns + privilege level to busaddress of device and particular subdevice according to spec of the device.*/
459 /* struct lun2dev_subdevice_map[] */
460 dev_subdevice_map = {
461 // .lun = 0, will trap
462 {{.lun = org_RiscV__Fallback__ReturnZero__lun, .priv = user}, .devAddr_interfId = {fallback, 1 /* ReturnZero */}},
463 {{.lun = org_RiscV__Fallback__ReturnZero__lun, .priv = super}, .devAddr_interfId = {fallback, 1 /* ReturnZero */}},
464 {{.lun = org_RiscV__Fallback__ReturnZero__lun, .priv = hyper}, .devAddr_interfId = {fallback, 1 /* ReturnZero */}},
465 {{.lun = org_RiscV__Fallback__ReturnZero__lun, .priv = mach}, .devAddr_interfId = {fallback, 1 /* ReturnZero */}},
466 {{.lun = org_RiscV__Fallback__ReturnMinusOne__lun, .priv = user}, .devAddr_interfId = {fallback, 2 /* ReturnMinusOne*/}},
467 {{.lun = org_RiscV__Fallback__ReturnMinusOne__lun, .priv = super}, .devAddr_interfId = {fallback, 2 /* ReturnMinusOne*/}},
468 {{.lun = org_RiscV__Fallback__ReturnMinusOne__lun, .priv = hyper}, .devAddr_interfId = {fallback, 2 /* ReturnMinusOne*/}},
469 {{.lun = org_RiscV__Fallback__ReturnMinusOne__lun, .priv = mach}, .devAddr_interfId = {fallback, 2 /* ReturnMinusOne*/}},
470 // .lun = 3 .. 7 reserved for other fallback RV interfaces
471 // .lun = 8 .. 30 reserved as error numbers, c.li t1 31; bltu rd t1 L_fail tests errors
472 // .lun = 31 reserved out of caution
473 {{.lun = cpu__Device1__Frobate__lun, .priv = user}, .devAddr_interfId = {device1, 0 /* Frobate interface */}},
474 {{.lun = cpu__Device1__Frobate__lun, .priv = super}, .devAddr_interfId = {device1, 0 /* Frobate interface */}},
475 {{.lun = cpu__Device1__Frobate__lun, .priv = hyper}, .devAddr_interfId = {device1, 0 /* Frobate interface */}},
476 {{.lun = cpu__Device1__Frobate__lun, .priv = mach}, .devAddr_interfId = {device1,64 /* Frobate machine level */}},
477 {{.lun = cpu__Device1__RocknRoll__lun, .priv = user}, .devAddr_InterfId = {device1, 1 /* RocknRoll interface */}},
478 {{.lun = cpu__Device1__RocknRoll__lun, .priv = super}, .devAddr_InterfId = {device1, 1 /* RocknRoll interface */}},
479 {{.lun = cpu__Device1__RocknRoll__lun, .priv = hyper}, .devAddr_InterfId = {device1, 1 /* RocknRoll interface */}},
480 {{.lun = cpu__Device1__RocknRoll__lun, .priv = super}, .devAddr_interfId = {device2, 1 /* Frobate interface */}},
481 {{.lun = cpu__Device2__Frobate__lun, .priv = super}, .devAddr_interfId = {device2, 0 /* Frobate interface */}},
482 {{.lun = cpu__Device2__Frobate__lun, .priv = hyper}, .devAddr_interfId = {device2, 0 /* Frobate interface */}},
483 {{.lun = cpu__Device2__Frobate__lun, .priv = mach}, .devAddr_interfId = {device2, 0 /* Frobate interface */}},
484 {{.lun = cpu__Device2__Jazz__lun, .priv = super}, .devAddr_interfId = {device2, 1 /* Jazz interface */}},
485 {{.lun = cpu__Device2__Jazz__lun, .priv = hyper}, .devAddr_interfId = {device2, 1 /* Jazz interface */}},
486 }