authorgravatar for koachan@protonmail.comKoakuma <koachan@protonmail.com> 2022-03-13 00:40:19+07:00
committergravatar for koachan@protonmail.comKoakuma <koachan@protonmail.com> 2022-03-16 21:38:41+07:00
loga212d5931d99653de28933499a2a0bded1b8d2db
tree60963a4b9cd8e68c2cdd3489f5ca701bb69df141
parent8a43d67c3bf878fa32ef4876897a32969a4b5d24

stage2 sparcv9: Add register definitions & instruction formats

This adds the GPR/FPR register definitions and instruction formats for SPARCv9. I need to implement a separate enc() function because the register values for the FPRs have to be encoded to a special format that's separate from the normal register ID.

1 files changed, 447 insertions(+), 0 deletions(-)

src/arch/sparcv9/bits.zig created+447
......@@ -0,0 +1,447 @@
1const std = @import("std");
2const DW = std.dwarf;
3const testing = std.testing;
4
5/// General purpose registers in the SPARCv9 instruction set
6pub const Register = enum(u6) {
7 // zig fmt: off
8 g0, g1, g2, g3, g4, g5, g6, g7,
9 o0, o1, o2, o3, o4, o5, o6, o7,
10 l0, l1, l2, l3, l4, l5, l6, l7,
11 @"i0", @"i1", @"i2", @"i3", @"i4", @"i5", @"i6", @"i7",
12
13 sp = 46, // stack pointer (o6)
14 fp = 62, // frame pointer (i6)
15 // zig fmt: on
16
17 pub fn id(self: Register) u5 {
18 return @truncate(u5, @enumToInt(self));
19 }
20
21 pub fn enc(self: Register) u5 {
22 // For integer registers, enc() == id().
23 return self.id();
24 }
25
26 pub fn dwarfLocOp(reg: Register) u8 {
27 return @as(u8, reg.id()) + DW.OP.reg0;
28 }
29};
30
31test "Register.id" {
32 // SP
33 try testing.expectEqual(@as(u5, 14), Register.o6.id());
34 try testing.expectEqual(Register.o6.id(), Register.sp.id());
35
36 // FP
37 try testing.expectEqual(@as(u5, 30), Register.@"i6".id());
38 try testing.expectEqual(Register.@"i6".id(), Register.fp.id());
39
40 // x0
41 try testing.expectEqual(@as(u5, 0), Register.g0.id());
42 try testing.expectEqual(@as(u5, 8), Register.o0.id());
43 try testing.expectEqual(@as(u5, 16), Register.l0.id());
44 try testing.expectEqual(@as(u5, 24), Register.@"i0".id());
45}
46
47test "Register.enc" {
48 // x0
49 try testing.expectEqual(@as(u5, 0), Register.g0.enc());
50 try testing.expectEqual(@as(u5, 8), Register.o0.enc());
51 try testing.expectEqual(@as(u5, 16), Register.l0.enc());
52 try testing.expectEqual(@as(u5, 24), Register.@"i0".enc());
53
54 // For integer registers, enc() == id().
55 try testing.expectEqual(Register.g0.enc(), Register.g0.id());
56 try testing.expectEqual(Register.o0.enc(), Register.o0.id());
57 try testing.expectEqual(Register.l0.enc(), Register.l0.id());
58 try testing.expectEqual(Register.@"i0".enc(), Register.@"i0".id());
59}
60
61/// Scalar floating point registers in the SPARCv9 instruction set
62pub const FloatingPointRegister = enum(u7) {
63 // SPARCv9 has 64 f32 registers, 32 f64 registers, and 16 f128 registers,
64 // which are aliased in this way:
65 //
66 // | %d0 | %d2 |
67 // %q0 | %f0 | %f1 | %f2 | %f3 |
68 // | %d4 | %d6 |
69 // %q4 | %f4 | %f5 | %f6 | %f7 |
70 // ...
71 // | %d60 | %d62 |
72 // %q60 | %f60 | %f61 | %f62 | %f63 |
73 //
74 // Though, since the instructions uses five-bit addressing, only %f0-%f31
75 // is usable with f32 instructions.
76
77 // zig fmt: off
78
79 // 32-bit registers
80 @"f0", @"f1", @"f2", @"f3", @"f4", @"f5", @"f6", @"f7",
81 @"f8", @"f9", @"f10", @"f11", @"f12", @"f13", @"f14", @"f15",
82 @"f16", @"f17", @"f18", @"f19", @"f20", @"f21", @"f22", @"f23",
83 @"f24", @"f25", @"f26", @"f27", @"f28", @"f29", @"f30", @"f31",
84
85 // 64-bit registers
86 d0, d2, d4, d6, d8, d10, d12, d14,
87 d16, d18, d20, d22, d24, d26, d28, d30,
88 d32, d34, d36, d38, d40, d42, d44, d46,
89 d48, d50, d52, d54, d56, d58, d60, d62,
90
91 // 128-bit registers
92 q0, q4, q8, q12, q16, q20, q24, q28,
93 q32, q36, q40, q44, q48, q52, q56, q60,
94 // zig fmt: on
95
96 pub fn id(self: FloatingPointRegister) u6 {
97 return switch (self.size()) {
98 32 => @truncate(u6, @enumToInt(self)),
99 64 => @truncate(u6, (@enumToInt(self) - 32) * 2),
100 128 => @truncate(u6, (@enumToInt(self) - 64) * 4),
101 else => unreachable,
102 };
103 }
104
105 pub fn enc(self: FloatingPointRegister) u5 {
106 // Floating point registers use an encoding scheme to map from the 6-bit
107 // ID to 5-bit encoded value.
108 // (See section 5.1.4.1 of SPARCv9 ISA specification)
109
110 const reg_id = self.id();
111 return @truncate(u5, reg_id | (reg_id >> 5));
112 }
113
114 /// Returns the bit-width of the register.
115 pub fn size(self: FloatingPointRegister) u8 {
116 return switch (@enumToInt(self)) {
117 0...31 => 32,
118 32...63 => 64,
119 64...79 => 128,
120 else => unreachable,
121 };
122 }
123};
124
125test "FloatingPointRegister.id" {
126 // Low region
127 try testing.expectEqual(@as(u6, 0), FloatingPointRegister.q0.id());
128 try testing.expectEqual(FloatingPointRegister.q0.id(), FloatingPointRegister.d0.id());
129 try testing.expectEqual(FloatingPointRegister.d0.id(), FloatingPointRegister.@"f0".id());
130
131 try testing.expectEqual(@as(u6, 28), FloatingPointRegister.q28.id());
132 try testing.expectEqual(FloatingPointRegister.q28.id(), FloatingPointRegister.d28.id());
133 try testing.expectEqual(FloatingPointRegister.d28.id(), FloatingPointRegister.@"f28".id());
134
135 // High region
136 try testing.expectEqual(@as(u6, 32), FloatingPointRegister.q32.id());
137 try testing.expectEqual(FloatingPointRegister.q32.id(), FloatingPointRegister.d32.id());
138
139 try testing.expectEqual(@as(u6, 60), FloatingPointRegister.q60.id());
140 try testing.expectEqual(FloatingPointRegister.q60.id(), FloatingPointRegister.d60.id());
141}
142
143test "FloatingPointRegister.enc" {
144 // f registers
145 try testing.expectEqual(@as(u5, 0), FloatingPointRegister.@"f0".enc());
146 try testing.expectEqual(@as(u5, 1), FloatingPointRegister.@"f1".enc());
147 try testing.expectEqual(@as(u5, 31), FloatingPointRegister.@"f31".enc());
148
149 // d registers
150 try testing.expectEqual(@as(u5, 0), FloatingPointRegister.d0.enc());
151 try testing.expectEqual(@as(u5, 1), FloatingPointRegister.d32.enc());
152 try testing.expectEqual(@as(u5, 31), FloatingPointRegister.d62.enc());
153
154 // q registers
155 try testing.expectEqual(@as(u5, 0), FloatingPointRegister.q0.enc());
156 try testing.expectEqual(@as(u5, 1), FloatingPointRegister.q32.enc());
157 try testing.expectEqual(@as(u5, 29), FloatingPointRegister.q60.enc());
158}
159
160/// Represents an instruction in the SPARCv9 instruction set
161pub const Instruction = union(enum) {
162 // Some of the instruction formats have several minor formats, here I
163 // name them with letters since there's no official naming scheme.
164 // TODO: need to rename the minor formats to a more descriptive name.
165
166 // Format 1 (op = 1): CALL
167 format_1: packed struct {
168 op: u2 = 0b01,
169 disp30: u30,
170 },
171
172 // Format 2 (op = 0): SETHI & Branches (Bicc, BPcc, BPr, FBfcc, FBPfcc)
173 format_2a: packed struct {
174 op: u2 = 0b00,
175 rd: u5,
176 op2: u3,
177 imm22: u22,
178 },
179 format_2b: packed struct {
180 op: u2 = 0b00,
181 a: u1,
182 cond: u4,
183 op2: u3,
184 disp22: u22,
185 },
186 format_2c: packed struct {
187 op: u2 = 0b00,
188 a: u1,
189 cond: u4,
190 op2: u3,
191 cc1: u1,
192 cc0: u1,
193 p: u1,
194 disp19: u19,
195 },
196 format_2d: packed struct {
197 op: u2 = 0b00,
198 a: u1,
199 fixed: u1 = 0b0,
200 rcond: u3,
201 op2: u3,
202 d16hi: u2,
203 p: u1,
204 rs1: u5,
205 d16lo: u14,
206 },
207
208 // Format 3 (op = 2 or 3): Arithmetic, Logical, MOVr, MEMBAR, Load, and Store
209 format_3a: packed struct {
210 op: u2,
211 rd: u5,
212 op3: u6,
213 rs1: u5,
214 i: u1 = 0b0,
215 reserved: u8 = 0b00000000,
216 rs2: u5,
217 },
218 format_3b: packed struct {
219 op: u2,
220 rd: u5,
221 op3: u6,
222 rs1: u5,
223 i: u1 = 0b1,
224 simm13: u13,
225 },
226 format_3c: packed struct {
227 op: u2,
228 reserved1: u5 = 0b00000,
229 op3: u6,
230 rs1: u5,
231 i: u1 = 0b0,
232 reserved2: u8 = 0b00000000,
233 rs2: u5,
234 },
235 format_3d: packed struct {
236 op: u2,
237 reserved: u5 = 0b00000,
238 op3: u6,
239 rs1: u5,
240 i: u1 = 0b1,
241 simm13: u13,
242 },
243 format_3e: packed struct {
244 op: u2,
245 rd: u5,
246 op3: u6,
247 rs1: u5,
248 i: u1 = 0b0,
249 rcond: u3,
250 reserved: u5 = 0b00000,
251 rs2: u5,
252 },
253 format_3f: packed struct {
254 op: u2,
255 rd: u5,
256 op3: u6,
257 rs1: u5,
258 i: u1 = 0b1,
259 rcond: u3,
260 simm10: u10,
261 },
262 format_3g: packed struct {
263 op: u2,
264 rd: u5,
265 op3: u6,
266 rs1: u5,
267 i: u1 = 0b1,
268 reserved: u8 = 0b00000000,
269 rs2: u5,
270 },
271 format_3h: packed struct {
272 op: u2,
273 rd: u5,
274 op3: u6,
275 rs1: u5,
276 i: u1 = 0b1,
277 reserved: u6,
278 cmask: u3,
279 mmask: u4,
280 },
281 format_3i: packed struct {
282 op: u2,
283 rd: u5,
284 op3: u6,
285 rs1: u5,
286 i: u1 = 0b0,
287 imm_asi: u8,
288 rs2: u5,
289 },
290 format_3j: packed struct {
291 op: u2,
292 impl_dep1: u5,
293 op3: u6,
294 impl_dep2: u19,
295 },
296 format_3k: packed struct {
297 op: u2,
298 rd: u5,
299 op3: u6,
300 rs1: u5,
301 i: u1 = 0b0,
302 x: u1,
303 reserved: u7 = 0b0000000,
304 rs2: u5,
305 },
306 format_3l: packed struct {
307 op: u2,
308 rd: u5,
309 op3: u6,
310 rs1: u5,
311 i: u1 = 0b1,
312 x: u1 = 0b0,
313 reserved: u7 = 0b0000000,
314 shcnt32: u5,
315 },
316 format_3m: packed struct {
317 op: u2,
318 rd: u5,
319 op3: u6,
320 rs1: u5,
321 i: u1 = 0b1,
322 x: u1 = 0b1,
323 reserved: u6 = 0b000000,
324 shcnt64: u6,
325 },
326 format_3n: packed struct {
327 op: u2,
328 rd: u5,
329 op3: u6,
330 reserved: u5 = 0b00000,
331 opf: u9,
332 rs2: u5,
333 },
334 format_3o: packed struct {
335 op: u2,
336 fixed: u3 = 0b000,
337 cc1: u1,
338 cc0: i1,
339 op3: u6,
340 opf: u9,
341 rs2: u5,
342 },
343 format_3p: packed struct {
344 op: u2,
345 rd: u5,
346 op3: u6,
347 rs1: u5,
348 opf: u9,
349 rs2: u5,
350 },
351 format_3q: packed struct {
352 op: u2,
353 rd: u5,
354 op3: u6,
355 rs1: u5,
356 reserved: u14 = 0b00000000000000,
357 },
358 format_3r: packed struct {
359 op: u2,
360 fcn: u5,
361 op3: u6,
362 reserved: u19 = 0b0000000000000000000,
363 },
364 format_3s: packed struct {
365 op: u2,
366 rd: u5,
367 op3: u6,
368 reserved: u19 = 0b0000000000000000000,
369 },
370
371 //Format 4 (op = 2): MOVcc, FMOVr, FMOVcc, and Tcc
372 format_4a: packed struct {
373 op: u2 = 0b10,
374 rd: u5,
375 op3: u6,
376 rs1: u5,
377 i: u1 = 0b0,
378 cc1: u1,
379 cc0: u1,
380 reserved: u6 = 0b000000,
381 rs2: u5,
382 },
383 format_4b: packed struct {
384 op: u2 = 0b10,
385 rd: u5,
386 op3: u6,
387 rs1: u5,
388 i: u1 = 0b1,
389 cc1: u1,
390 cc0: u1,
391 simm11: u11,
392 },
393 format_4c: packed struct {
394 op: u2 = 0b10,
395 rd: u5,
396 op3: u6,
397 cc2: u1,
398 cond: u4,
399 i: u1 = 0b0,
400 cc1: u1,
401 cc0: u1,
402 reserved: u6 = 0b000000,
403 rs2: u5,
404 },
405 format_4d: packed struct {
406 op: u2 = 0b10,
407 rd: u5,
408 op3: u6,
409 cc2: u1,
410 cond: u4,
411 i: u1 = 0b1,
412 cc1: u1,
413 cc0: u1,
414 simm11: u11,
415 },
416 format_4e: packed struct {
417 op: u2 = 0b10,
418 rd: u5,
419 op3: u6,
420 rs1: u5,
421 i: u1 = 0b1,
422 cc1: u1,
423 cc0: u1,
424 reserved: u4 = 0b0000,
425 sw_trap: u7,
426 },
427 format_4f: packed struct {
428 op: u2 = 0b10,
429 rd: u5,
430 op3: u6,
431 rs1: u5,
432 fixed: u1 = 0b0,
433 rcond: u3,
434 opf_low: u5,
435 rs2: u5,
436 },
437 format_4g: packed struct {
438 op: u2 = 0b10,
439 rd: u5,
440 op3: u6,
441 fixed: u1 = 0b0,
442 cond: u4,
443 opf_cc: u3,
444 opf_low: u6,
445 rs2: u5,
446 },
447};