1use memoffset::{offset_of};
7
8use super::code::{UnaryOp, BinaryOp, Width, Register, REGISTERS, GLOBAL, EBB, Marshal};
9use UnaryOp::*;
10use BinaryOp::*;
11use Width::*;
12use super::target::{Word, Target};
13use super::jit::{EntryId, Jit};
14use super::code::builder::{build, build_block, Builder};
15
16mod registers;
17pub use registers::{Registers, M0Registers};
18
19pub const CELL: i32 = 4;
21
22pub const CELL_BITS: i32 = CELL * 8;
24
25const R1: Register = REGISTERS[1];
28const R2: Register = REGISTERS[2];
29const R3: Register = REGISTERS[3];
30const BEP: Register = REGISTERS[4];
31const BI: Register = REGISTERS[5];
32const BA: Register = REGISTERS[6];
33const BSP: Register = REGISTERS[7];
34const BRP: Register = REGISTERS[8];
35const M0: Register = REGISTERS[9];
36const REGS: Register = REGISTERS[10];
37
38macro_rules! register {
40 ($field: ident) => {
41 (REGS, offset_of!(Registers, $field) as i32 + 8, Four)
42 }
43}
44
45const NOT_IMPLEMENTED: i64 = 0;
47const UNDEFINED: i64 = i64::MAX;
49
50fn native_address(b: &mut Builder<EntryId>, addr: Register) {
54 b.binary64(Add, BI, M0, addr);
55}
56
57fn load(b: &mut Builder<EntryId>, dest: Register, addr: Register) {
59 native_address(b, addr);
60 b.load(dest, (BI, 0, Four));
61 b.send(M0, BI);
62}
63
64fn store(b: &mut Builder<EntryId>, src: Register, addr: Register) {
66 native_address(b, addr);
67 b.store(src, (BI, 0, Four));
68 b.send(M0, BI);
69}
70
71fn pop(b: &mut Builder<EntryId>, dest: Register, sp: Register) {
73 load(b, dest, sp);
74 b.const_binary32(Add, sp, sp, CELL);
75}
76
77fn push(b: &mut Builder<EntryId>, src: Register, sp: Register) {
79 b.const_binary32(Sub, sp, sp, CELL);
80 store(b, src, sp);
81}
82
83#[derive(Debug)]
85pub struct Beetle<T: Target> {
86 pub jit: Jit<T>,
87 pub root: EntryId,
88}
89
90impl<T: Target> Beetle<T> {
91 #[allow(clippy::too_many_lines)]
92 pub fn new(target: T) -> Self {
93 let mut jit = Jit::new(target);
94 let marshal = Marshal {
95 prologue: build_block(|b| {
96 b.move_(REGS, GLOBAL);
97 b.load(BEP, register!(ep));
98 b.load(BI, register!(i));
99 b.load(BA, register!(a));
100 b.load(BSP, register!(sp));
101 b.load(BRP, register!(rp));
102 b.load(M0, (REGS, 0, Eight));
103 }),
104 epilogue: build_block(|b| {
105 b.store(BEP, register!(ep));
106 b.store(BI, register!(i));
107 b.store(BA, register!(a));
108 b.store(BSP, register!(sp));
109 b.store(BRP, register!(rp));
110 b.send(REGS, M0);
112 b.move_(GLOBAL, REGS);
113 }),
114 };
115 let root = jit.new_entry(&marshal, UNDEFINED);
116
117 let branchi = jit.new_entry(&marshal, UNDEFINED);
119 jit.define(branchi, &build(|mut b| {
120 b.const_binary32(Mul, R1, BA, CELL);
121 b.binary32(Add, BEP, BEP, R1);
122 pop(&mut b, BA, BEP);
123 b.jump(root)
124 }));
125
126 let not_implemented2 = jit.new_entry(&marshal, NOT_IMPLEMENTED);
128 let not_implemented = jit.new_entry(&marshal, UNDEFINED);
129 jit.define(not_implemented, &build(|mut b| {
130 b.const_binary32(Lsl, BA, BA, 8);
131 b.binary32(Or, BA, BA, BI);
132 b.jump(not_implemented2)
133 }));
134
135 let mut actions: Box<[EBB<EntryId>]> = (0..0x63).map(|_| {
137 build(|b| b.jump(not_implemented))
138 }).collect();
139
140 actions[0x00] = build(|mut b| {
142 pop(&mut b, BA, BEP);
143 b.jump(root)
144 });
145
146 actions[0x01] = build(|mut b| {
148 load(&mut b, R2, BSP);
149 push(&mut b, R2, BSP);
150 b.jump(root)
151 });
152
153 actions[0x02] = build(|mut b| {
155 b.const_binary32(Add, BSP, BSP, CELL);
156 b.jump(root)
157 });
158
159 actions[0x03] = build(|mut b| {
161 pop(&mut b, R2, BSP);
162 load(&mut b, R3, BSP);
163 store(&mut b, R2, BSP);
164 push(&mut b, R3, BSP);
165 b.jump(root)
166 });
167
168 actions[0x04] = build(|mut b| {
170 b.const_binary32(Add, R1, BSP, CELL);
171 load(&mut b, R2, R1);
172 push(&mut b, R2, BSP);
173 b.jump(root)
174 });
175
176 actions[0x05] = build(|mut b| {
178 load(&mut b, R2, BSP);
179 b.const_binary32(Add, R1, BSP, CELL);
180 load(&mut b, R3, R1);
181 store(&mut b, R2, R1);
182 b.const_binary32(Add, R1, BSP, 2 * CELL);
183 load(&mut b, R2, R1);
184 store(&mut b, R3, R1);
185 store(&mut b, R2, BSP);
186 b.jump(root)
187 });
188
189 actions[0x06] = build(|mut b| {
191 load(&mut b, R2, BSP);
192 b.const_binary32(Add, R1, BSP, 2 * CELL);
193 load(&mut b, R3, R1);
194 store(&mut b, R2, R1);
195 b.const_binary32(Add, R1, BSP, CELL);
196 load(&mut b, R2, R1);
197 store(&mut b, R3, R1);
198 store(&mut b, R2, BSP);
199 b.jump(root)
200 });
201
202 actions[0x07] = build(|mut b| {
204 load(&mut b, R2, BSP);
205 b.const_binary32(Add, R1, BSP, CELL);
206 load(&mut b, R3, R1);
207 store(&mut b, R2, R1);
208 store(&mut b, R3, BSP);
209 push(&mut b, R2, BSP);
210 b.jump(root)
211 });
212
213 actions[0x08] = build(|mut b| {
215 pop(&mut b, R2, BSP);
216 store(&mut b, R2, BSP);
217 b.jump(root)
218 });
219
220 actions[0x0F] = build(|mut b| {
222 pop(&mut b, R2, BSP);
223 load(&mut b, R3, BSP);
224 b.binary32(Lt, R2, R3, R2);
225 store(&mut b, R2, BSP);
226 b.jump(root)
227 });
228
229 actions[0x10] = build(|mut b| {
231 pop(&mut b, R2, BSP);
232 load(&mut b, R3, BSP);
233 b.binary32(Lt, R2, R2, R3);
234 store(&mut b, R2, BSP);
235 b.jump(root)
236 });
237
238 actions[0x11] = build(|mut b| {
240 pop(&mut b, R2, BSP);
241 load(&mut b, R3, BSP);
242 b.binary32(Eq, R2, R3, R2);
243 store(&mut b, R2, BSP);
244 b.jump(root)
245 });
246
247 actions[0x12] = build(|mut b| {
249 pop(&mut b, R2, BSP);
250 load(&mut b, R3, BSP);
251 b.binary32(Eq, R2, R3, R2);
252 b.unary32(Not, R2, R2);
253 store(&mut b, R2, BSP);
254 b.jump(root)
255 });
256
257 actions[0x13] = build(|mut b| {
259 load(&mut b, R2, BSP);
260 b.const_binary32(Lt, R2, R2, 0);
261 store(&mut b, R2, BSP);
262 b.jump(root)
263 });
264
265 actions[0x14] = build(|mut b| {
267 load(&mut b, R2, BSP);
268 b.const_(R3, 0);
269 b.binary32(Lt, R2, R3, R2);
270 store(&mut b, R2, BSP);
271 b.jump(root)
272 });
273
274 actions[0x15] = build(|mut b| {
276 load(&mut b, R2, BSP);
277 b.const_binary32(Eq, R2, R2, 0);
278 store(&mut b, R2, BSP);
279 b.jump(root)
280 });
281
282 actions[0x16] = build(|mut b| {
284 load(&mut b, R2, BSP);
285 b.const_binary32(Eq, R2, R2, 0);
286 b.unary32(Not, R2, R2);
287 store(&mut b, R2, BSP);
288 b.jump(root)
289 });
290
291 actions[0x17] = build(|mut b| {
293 pop(&mut b, R2, BSP);
294 load(&mut b, R3, BSP);
295 b.binary32(Ult, R2, R3, R2);
296 store(&mut b, R2, BSP);
297 b.jump(root)
298 });
299
300 actions[0x18] = build(|mut b| {
302 pop(&mut b, R2, BSP);
303 load(&mut b, R3, BSP);
304 b.binary32(Ult, R2, R2, R3);
305 store(&mut b, R2, BSP);
306 b.jump(root)
307 });
308
309 actions[0x19] = build(|mut b| {
311 b.const_(R2, 0);
312 push(&mut b, R2, BSP);
313 b.jump(root)
314 });
315
316 actions[0x1A] = build(|mut b| {
318 b.const_(R2, 1);
319 push(&mut b, R2, BSP);
320 b.jump(root)
321 });
322
323 actions[0x1B] = build(|mut b| {
325 b.const_(R2, -1i32 as u32 as i64);
326 push(&mut b, R2, BSP);
327 b.jump(root)
328 });
329
330 actions[0x1E] = build(|mut b| {
332 pop(&mut b, R2, BSP);
333 load(&mut b, R3, BSP);
334 b.binary32(Add, R2, R3, R2);
335 store(&mut b, R2, BSP);
336 b.jump(root)
337 });
338
339 actions[0x1F] = build(|mut b| {
341 pop(&mut b, R2, BSP);
342 load(&mut b, R3, BSP);
343 b.binary32(Sub, R2, R3, R2);
344 store(&mut b, R2, BSP);
345 b.jump(root)
346 });
347
348 actions[0x20] = build(|mut b| {
350 pop(&mut b, R2, BSP);
351 load(&mut b, R3, BSP);
352 b.binary32(Sub, R2, R2, R3);
353 store(&mut b, R2, BSP);
354 b.jump(root)
355 });
356
357 actions[0x21] = build(|mut b| {
359 load(&mut b, R2, BSP);
360 b.const_binary32(Add, R2, R2, 1);
361 store(&mut b, R2, BSP);
362 b.jump(root)
363 });
364
365 actions[0x22] = build(|mut b| {
367 load(&mut b, R2, BSP);
368 b.const_binary32(Sub, R2, R2, 1);
369 store(&mut b, R2, BSP);
370 b.jump(root)
371 });
372
373 actions[0x25] = build(|mut b| {
375 pop(&mut b, R2, BSP);
376 load(&mut b, R3, BSP);
377 b.binary32(Mul, R2, R3, R2);
378 store(&mut b, R2, BSP);
379 b.jump(root)
380 });
381
382 actions[0x2D] = build(|mut b| {
384 load(&mut b, R2, BSP);
385 b.unary32(Abs, R2, R2);
386 store(&mut b, R2, BSP);
387 b.jump(root)
388 });
389
390 actions[0x2E] = build(|mut b| {
392 load(&mut b, R2, BSP);
393 b.unary32(Negate, R2, R2);
394 store(&mut b, R2, BSP);
395 b.jump(root)
396 });
397
398 actions[0x2F] = build(|mut b| {
400 pop(&mut b, R2, BSP);
401 load(&mut b, R3, BSP);
402 b.binary32(Max, R2, R3, R2);
403 store(&mut b, R2, BSP);
404 b.jump(root)
405 });
406
407 actions[0x30] = build(|mut b| {
409 pop(&mut b, R2, BSP);
410 load(&mut b, R3, BSP);
411 b.binary32(Min, R2, R3, R2);
412 store(&mut b, R2, BSP);
413 b.jump(root)
414 });
415
416 actions[0x31] = build(|mut b| {
418 load(&mut b, R2, BSP);
419 b.unary32(Not, R2, R2);
420 store(&mut b, R2, BSP);
421 b.jump(root)
422 });
423
424 actions[0x39] = build(|mut b| {
426 load(&mut b, R2, BSP);
427 load(&mut b, R2, R2);
428 store(&mut b, R2, BSP);
429 b.jump(root)
430 });
431
432 actions[0x3A] = build(|mut b| {
434 pop(&mut b, R2, BSP);
435 pop(&mut b, R3, BSP);
436 store(&mut b, R3, R2);
437 b.jump(root)
438 });
439
440 actions[0x3D] = build(|mut b| {
442 pop(&mut b, R2, BSP);
443 pop(&mut b, R3, BSP);
444 load(&mut b, R1, R2);
445 b.binary32(Add, R3, R1, R3);
446 store(&mut b, R3, R2);
447 b.jump(root)
448 });
449
450 actions[0x43] = build(|b| { b.jump(branchi) });
452
453 actions[0x45] = build(|mut b| {
455 pop(&mut b, BI, BSP);
456 b.if_(BI,
457 build(|mut b| {
458 pop(&mut b, BA, BEP);
459 b.jump(root)
460 }),
461 build(|b| { b.jump(branchi) }),
462 )
463 });
464
465 actions[0x49] = build(|mut b| {
467 push(&mut b, BEP, BRP);
468 b.jump(branchi)
469 });
470
471 actions[0x4A] = build(|mut b| {
473 pop(&mut b, BEP, BRP);
474 pop(&mut b, BA, BEP);
475 b.jump(root)
476 });
477
478 actions[0x53] = build(|mut b| {
480 push(&mut b, BA, BSP);
481 pop(&mut b, BA, BEP);
482 b.jump(root)
483 });
484
485 jit.define(root, &build(|mut b| {
487 b.const_binary32(And, BI, BA, 0xFF);
488 b.const_binary32(Asr, BA, BA, 8);
489 b.index(BI, actions, build(|b| b.jump(not_implemented)))
490 }));
491
492 Self {jit, root}
493 }
494
495 pub unsafe fn run(&mut self, registers: &mut M0Registers) {
499 let result = self.jit.run(self.root, registers);
500 assert_eq!(result, Word {s: NOT_IMPLEMENTED});
501 }
502}
503
504#[cfg(test)]
507mod tests;