1pub mod cpu;
2
3#[cfg(test)]
4mod test {
5 extern crate elfloader;
6
7 use super::cpu::*;
8 use super::cpu::instruction::Instruction;
9
10 use elfloader::*;
11 use std::io::Write;
12
13 const MAX_SIZE: usize = 1024 * 128;
14 struct RVTestElfLoader {
15 target: [u8; MAX_SIZE],
16 pub img_base: u64
17 }
18
19 impl RVTestElfLoader {
20 pub fn new() -> Self {
21 RVTestElfLoader {
22 target: [0; MAX_SIZE],
23 img_base: u64::MAX
24 }
25 }
26
27 pub fn get_target(&mut self) -> *mut u32 {
28 unsafe {
29 std::mem::transmute::<&u8, *mut u32>(&self.target[0])
30 }
31 }
32 }
33
34 impl ElfLoader for RVTestElfLoader {
35 fn allocate(&mut self, load_headers: LoadableHeaders) -> Result<(), &'static str> {
36 for header in load_headers {
37 if header.virtual_addr() < self.img_base {
38 self.img_base = header.virtual_addr();
39 }
40 }
41
42 Ok(())
43 }
44
45 fn relocate(&mut self, _entry: &Rela<P64>) -> Result<(), &'static str> {
46 Err("Unexpected relocation encountered")
50
51 }
52
53 fn load(&mut self, _flags: Flags, base: VAddr, region: &[u8]) -> Result<(), &'static str> {
54 let start = base - self.img_base;
55 let end = start + region.len() as u64;
56
57 if end < MAX_SIZE as u64 {
59 for i in 0..region.len() {
60 self.target[start as usize + i] = region[i];
61 }
62
63 Ok(())
64 } else {
65 Err("Image will not fit")
66 }
67 }
68
69 fn tls(
70 &mut self,
71 _tdata_start: VAddr,
72 _tdata_length: u64,
73 _total_size: u64,
74 _align: u64
75 ) -> Result<(), &'static str> {
76 Err("TLS region")
81 }
82
83 }
84
85 fn run_test(binary_blob: &[u8]) {
86 let binary = ElfBinary::new("test", binary_blob).expect("Got proper ELF file");
87 let mut loader = RVTestElfLoader::new();
88 binary.load(&mut loader).expect("Can't load the binary?");
89 let img_base = loader.img_base;
90
91 let entry_point_offset = binary.entry_point() - img_base;
92
93 let mut cpu = Cpu::new();
94 cpu.set_ecall_handler(Some(Instruction{
95 name: "ECALL",
96 operation: |cpu, _word, _address| {
97 match cpu.get_register(Register::A7) {
98 64 => Ok(()), 93 => Err(Trap { trap_type: TrapType::Stop, value: cpu.get_register(Register::A0) as u64 }),
100 num => Err(Trap { trap_type: TrapType::SupervisorSoftwareInterrupt, value: num as u64})
101 }
102 }
103 }));
104
105 let img = loader.get_target();
106 let base_pc = img as usize;
107 let entry_point = (base_pc as u64 + entry_point_offset) as *mut u32;
108 cpu.update_pc(entry_point);
109 let mut stack = Vec::with_capacity(1024*1024);
110 stack.resize(1024*1024, 0);
111 cpu.set_stack(stack);
112 let mut fuel = 1_000_000_000;
113
114 let dump_instructions = std::env::var("DUMP_INSTRUCTIONS").is_ok();
115 let mut old_x = cpu.x.clone();
116 let mut old_f = cpu.f.clone();
117
118 loop {
119 let pc = cpu.get_pc() - base_pc + img_base as usize;
120
121 if dump_instructions {
122 let saved = cpu.pc;
123 let op = cpu.fetch();
124 let inst = Cpu::decode(op);
125 cpu.pc = saved;
126
127 if let Some(inst) = inst {
128 print!("pc = {:#x} - {:?}, Cpu - x: [", pc, inst.name);
129 for i in 0..32 {
130 if i > 0 {
131 print!(", ");
132 }
133 if cpu.x[i] == old_x[i] {
134 print!("{:?}", cpu.x[i]);
135 } else {
136 print!("\x1b[31m{:?}\x1b[0m", cpu.x[i]);
137 }
138 }
139 print!("], f: [");
140 for i in 0..32 {
141 if i > 0 {
142 print!(", ");
143 }
144 if cpu.f[i].to_bits() == old_f[i].to_bits() {
145 print!("{:?}", cpu.f[i]);
146 } else {
147 print!("\x1b[31m{:?}\x1b[0m", cpu.f[i]);
148 }
149 }
150 println!("]");
151 }
152
153 old_x = cpu.x.clone();
154 old_f = cpu.f.clone();
155 std::io::stdout().flush().expect("flush");
156 }
157
158 match cpu.tick() {
159 Ok(_) => {
160 fuel = fuel - 1;
161 if fuel == 0 {
162 panic!("out of fuel");
163 }
164 },
165 Err(e) => {
166 match e.trap_type {
167 TrapType::Stop => {
168 if e.value != 0 {
169 panic!("CPU test {:?} failed a0={:#x} a1={:#x} a2={:#x} a3={:#x} a4={:#x} t2={:#x}", e.value >> 1, cpu.get_register(Register::A0), cpu.get_register(Register::A1), cpu.get_register(Register::A2), cpu.get_register(Register::A3), cpu.get_register(Register::A4), cpu.get_register(Register::T2));
170 } else {
171 break;
172 }
173 },
174 _ => panic!("CPU failure: pc = {:#x} - {:?}", pc, e)
175 }
176 }
177 }
178 }
179 }
180
181 macro_rules! rv_test {
182 ( $bytes:literal ) => {
183 let binary_blob = include_bytes!($bytes);
184
185 run_test(binary_blob);
186 }
187 }
188
189 mod rv64_ui_p {
190 use super::*;
191
192 #[test]
193 fn rv64ui_p_add() {
194 rv_test!("../test/rv64ui-p-add");
195 }
196
197 #[test]
198 fn rv64ui_p_addi() {
199 rv_test!("../test/rv64ui-p-addi");
200 }
201
202 #[test]
203 fn rv64ui_p_addiw() {
204 rv_test!("../test/rv64ui-p-addiw");
205 }
206
207 #[test]
208 fn rv64ui_p_addw() {
209 rv_test!("../test/rv64ui-p-addw");
210 }
211
212 #[test]
213 fn rv64ui_p_and() {
214 rv_test!("../test/rv64ui-p-and");
215 }
216
217 #[test]
218 fn rv64ui_p_andi() {
219 rv_test!("../test/rv64ui-p-andi");
220 }
221
222 #[test]
223 fn rv64ui_p_auipc() {
224 rv_test!("../test/rv64ui-p-auipc");
225 }
226
227 #[test]
228 fn rv64ui_p_beq() {
229 rv_test!("../test/rv64ui-p-beq");
230 }
231
232 #[test]
233 fn rv64ui_p_blt() {
234 rv_test!("../test/rv64ui-p-blt");
235 }
236
237 #[test]
238 fn rv64ui_p_bltu() {
239 rv_test!("../test/rv64ui-p-bltu");
240 }
241
242 #[test]
243 fn rv64ui_p_bne() {
244 rv_test!("../test/rv64ui-p-bne");
245 }
246
247 #[test]
248 fn rv64ui_p_fence_i() {
249 rv_test!("../test/rv64ui-p-fence_i");
250 }
251
252 #[test]
253 fn rv64ui_p_jal() {
254 rv_test!("../test/rv64ui-p-jal");
255 }
256
257 #[test]
258 fn rv64ui_p_jalr() {
259 rv_test!("../test/rv64ui-p-jalr");
260 }
261
262 #[test]
263 fn rv64ui_p_lb() {
264 rv_test!("../test/rv64ui-p-lb");
265 }
266
267 #[test]
268 fn rv64ui_p_lbu() {
269 rv_test!("../test/rv64ui-p-lbu");
270 }
271
272 #[test]
273 fn rv64ui_p_ld() {
274 rv_test!("../test/rv64ui-p-ld");
275 }
276
277 #[test]
278 fn rv64ui_p_lh() {
279 rv_test!("../test/rv64ui-p-lh");
280 }
281
282 #[test]
283 fn rv64ui_p_lhu() {
284 rv_test!("../test/rv64ui-p-lhu");
285 }
286
287 #[test]
288 fn rv64ui_p_lui() {
289 rv_test!("../test/rv64ui-p-lui");
290 }
291
292 #[test]
293 fn rv64ui_p_lw() {
294 rv_test!("../test/rv64ui-p-lw");
295 }
296
297 #[test]
298 fn rv64ui_p_lwu() {
299 rv_test!("../test/rv64ui-p-lwu");
300 }
301
302 #[test]
303 fn rv64ui_p_or() {
304 rv_test!("../test/rv64ui-p-or");
305 }
306
307 #[test]
308 fn rv64ui_p_ori() {
309 rv_test!("../test/rv64ui-p-ori");
310 }
311
312 #[test]
313 fn rv64ui_p_sb() {
314 rv_test!("../test/rv64ui-p-sb");
315 }
316
317 #[test]
318 fn rv64ui_p_sd() {
319 rv_test!("../test/rv64ui-p-sd");
320 }
321
322 #[test]
323 fn rv64ui_p_sh() {
324 rv_test!("../test/rv64ui-p-sh");
325 }
326
327 #[test]
328 fn rv64ui_p_simple() {
329 rv_test!("../test/rv64ui-p-simple");
330 }
331
332 #[test]
333 fn rv64ui_p_sll() {
334 rv_test!("../test/rv64ui-p-sll");
335 }
336
337 #[test]
338 fn rv64ui_p_slli() {
339 rv_test!("../test/rv64ui-p-slli");
340 }
341
342 #[test]
343 fn rv64ui_p_slliw() {
344 rv_test!("../test/rv64ui-p-slliw");
345 }
346
347 #[test]
348 fn rv64ui_p_sllw() {
349 rv_test!("../test/rv64ui-p-sllw");
350 }
351
352 #[test]
353 fn rv64ui_p_slt() {
354 rv_test!("../test/rv64ui-p-slt");
355 }
356
357 #[test]
358 fn rv64ui_p_slti() {
359 rv_test!("../test/rv64ui-p-slti");
360 }
361
362 #[test]
363 fn rv64ui_p_sltiu() {
364 rv_test!("../test/rv64ui-p-sltiu");
365 }
366
367 #[test]
368 fn rv64ui_p_sltu() {
369 rv_test!("../test/rv64ui-p-sltu");
370 }
371
372 #[test]
373 fn rv64ui_p_sra() {
374 rv_test!("../test/rv64ui-p-sra");
375 }
376
377 #[test]
378 fn rv64ui_p_srai() {
379 rv_test!("../test/rv64ui-p-srai");
380 }
381
382 #[test]
383 fn rv64ui_p_sraiw() {
384 rv_test!("../test/rv64ui-p-sraiw");
385 }
386
387 #[test]
388 fn rv64ui_p_sraw() {
389 rv_test!("../test/rv64ui-p-sraw");
390 }
391
392 #[test]
393 fn rv64ui_p_srl() {
394 rv_test!("../test/rv64ui-p-srl");
395 }
396
397 #[test]
398 fn rv64ui_p_srli() {
399 rv_test!("../test/rv64ui-p-srli");
400 }
401
402 #[test]
403 fn rv64ui_p_srliw() {
404 rv_test!("../test/rv64ui-p-srliw");
405 }
406
407 #[test]
408 fn rv64ui_p_srlw() {
409 rv_test!("../test/rv64ui-p-srlw");
410 }
411
412 #[test]
413 fn rv64ui_p_sub() {
414 rv_test!("../test/rv64ui-p-sub");
415 }
416
417 #[test]
418 fn rv64ui_p_subw() {
419 rv_test!("../test/rv64ui-p-subw");
420 }
421
422 #[test]
423 fn rv64ui_p_sw() {
424 rv_test!("../test/rv64ui-p-sw");
425 }
426
427 #[test]
428 fn rv64ui_p_xor() {
429 rv_test!("../test/rv64ui-p-xor");
430 }
431
432 #[test]
433 fn rv64ui_p_xori() {
434 rv_test!("../test/rv64ui-p-xori");
435 }
436 }
437
438 mod rv64_ua_p {
439 use super::*;
440
441 #[test]
442 fn rv64ua_p_amoadd_d() {
443 rv_test!("../test/rv64ua-p-amoadd_d");
444 }
445
446 #[test]
447 fn rv64ua_p_amoadd_w() {
448 rv_test!("../test/rv64ua-p-amoadd_w");
449 }
450
451 #[test]
452 fn rv64ua_p_amoand_d() {
453 rv_test!("../test/rv64ua-p-amoand_d");
454 }
455
456 #[test]
457 fn rv64ua_p_amoand_w() {
458 rv_test!("../test/rv64ua-p-amoadd_w");
459 }
460
461 #[test]
462 fn rv64ua_p_amomax_d() {
463 rv_test!("../test/rv64ua-p-amomax_d");
464 }
465
466 #[test]
467 fn rv64ua_p_amomax_w() {
468 rv_test!("../test/rv64ua-p-amomax_w");
469 }
470
471 #[test]
472 fn rv64ua_p_amomaxu_d() {
473 rv_test!("../test/rv64ua-p-amomaxu_d");
474 }
475
476 #[test]
477 fn rv64ua_p_amomaxu_w() {
478 rv_test!("../test/rv64ua-p-amomaxu_w");
479 }
480
481 #[test]
482 fn rv64ua_p_amomin_d() {
483 rv_test!("../test/rv64ua-p-amomin_d");
484 }
485
486 #[test]
487 fn rv64ua_p_amomin_w() {
488 rv_test!("../test/rv64ua-p-amomin_w");
489 }
490
491 #[test]
492 fn rv64ua_p_amominu_d() {
493 rv_test!("../test/rv64ua-p-amominu_d");
494 }
495
496 #[test]
497 fn rv64ua_p_amominu_w() {
498 rv_test!("../test/rv64ua-p-amominu_w");
499 }
500
501 #[test]
502 fn rv64ua_p_amoor_d() {
503 rv_test!("../test/rv64ua-p-amoor_d");
504 }
505
506 #[test]
507 fn rv64ua_p_amoor_w() {
508 rv_test!("../test/rv64ua-p-amoor_w");
509 }
510
511 #[test]
512 fn rv64ua_p_amoswap_d() {
513 rv_test!("../test/rv64ua-p-amoswap_d");
514 }
515
516 #[test]
517 fn rv64ua_p_amoswap_w() {
518 rv_test!("../test/rv64ua-p-amoswap_w");
519 }
520
521 #[test]
522 fn rv64ua_p_amoxor_d() {
523 rv_test!("../test/rv64ua-p-amoxor_d");
524 }
525
526 #[test]
527 fn rv64ua_p_amoxor_w() {
528 rv_test!("../test/rv64ua-p-amoxor_w");
529 }
530
531 #[test]
532 fn rv64ua_p_lrsc() {
533 rv_test!("../test/rv64ua-p-lrsc");
534 }
535 }
536
537 mod rv64_um_p {
538 use super::*;
539
540 #[test]
541 fn rv64um_p_div() {
542 rv_test!("../test/rv64um-p-div");
543 }
544
545 #[test]
546 fn rv64um_p_divu() {
547 rv_test!("../test/rv64um-p-divu");
548 }
549
550 #[test]
551 fn rv64um_p_divuw() {
552 rv_test!("../test/rv64um-p-divuw");
553 }
554
555 #[test]
556 fn rv64um_p_divw() {
557 rv_test!("../test/rv64um-p-divw");
558 }
559
560 #[test]
561 fn rv64um_p_mul() {
562 rv_test!("../test/rv64um-p-mul");
563 }
564
565 #[test]
566 fn rv64um_p_mulh() {
567 rv_test!("../test/rv64um-p-mulh");
568 }
569
570 #[test]
571 fn rv64um_p_mulhsu() {
572 rv_test!("../test/rv64um-p-mulhsu");
573 }
574
575 #[test]
576 fn rv64um_p_mulhu() {
577 rv_test!("../test/rv64um-p-mulhu");
578 }
579
580 #[test]
581 fn rv64um_p_mulw() {
582 rv_test!("../test/rv64um-p-mulw");
583 }
584
585 #[test]
586 fn rv64um_p_rem() {
587 rv_test!("../test/rv64um-p-rem");
588 }
589
590 #[test]
591 fn rv64um_p_remu() {
592 rv_test!("../test/rv64um-p-remu");
593 }
594
595 #[test]
596 fn rv64um_p_remuw() {
597 rv_test!("../test/rv64um-p-remuw");
598 }
599
600 #[test]
601 fn rv64um_p_remw() {
602 rv_test!("../test/rv64um-p-remw");
603 }
604 }
605
606 mod rv64_uc_p {
607 use super::*;
608
609 #[test]
610 fn rv64uc_p_rvc() {
611 rv_test!("../test/rv64uc-p-rvc");
612 }
613 }
614
615 mod rv64_uf_p {
616 use super::*;
617
618 #[test]
619 fn decode_frcsr() {
620 let inst = Cpu::decode(0x00302573);
622 assert!(inst.is_some());
623 assert_eq!("CSRRS", inst.unwrap().name);
624 let f = instruction::parse_format_csr(0x00302573);
625 assert_eq!(3, f.csr);
626 assert_eq!(0, f.rs);
627 assert_eq!(10, f.rd);
628 }
629
630 #[test]
631 fn rv64uf_p_ldst() {
632 rv_test!("../test/rv64uf-p-ldst");
633 }
634
635 #[test]
636 #[ignore]
637 fn rv64uf_p_move() {
638 rv_test!("../test/rv64uf-p-move");
639 }
640
641 #[test]
642 fn rv64uf_p_recoding() {
643 rv_test!("../test/rv64uf-p-recoding");
644 }
645
646 #[test]
647 fn rv64uf_p_fadd() {
648 rv_test!("../test/rv64uf-p-fadd");
649 }
650
651 #[test]
652 fn rv64uf_p_fcmp() {
653 rv_test!("../test/rv64uf-p-fcmp");
654 }
655
656 #[test]
657 fn rv64uf_p_fcvt() {
658 rv_test!("../test/rv64uf-p-fcvt");
659 }
660
661 #[test]
662 fn rv64uf_p_fcvt_w() {
663 rv_test!("../test/rv64uf-p-fcvt_w");
664 }
665
666 #[test]
667 fn rv64uf_p_fdiv() {
668 rv_test!("../test/rv64uf-p-fdiv");
669 }
670
671 #[test]
672 fn rv64uf_p_fmadd() {
673 rv_test!("../test/rv64uf-p-fmadd");
674 }
675
676 #[test]
677 fn rv64uf_p_fmin() {
678 rv_test!("../test/rv64uf-p-fmin");
679 }
680 }
681
682 mod rv64_ud_p {
683 use super::*;
684
685 #[test]
686 fn rv64ud_p_fadd() {
687 rv_test!("../test/rv64ud-p-fadd");
688 }
689
690 #[test]
691 fn rv64ud_p_fcmp() {
692 rv_test!("../test/rv64ud-p-fcmp");
693 }
694
695 #[test]
696 fn rv64ud_p_fcvt() {
697 rv_test!("../test/rv64ud-p-fcvt");
698 }
699
700 #[test]
701 fn rv64ud_p_fcvt_w() {
702 rv_test!("../test/rv64ud-p-fcvt_w");
703 }
704
705 #[test]
706 fn rv64ud_p_fdiv() {
707 rv_test!("../test/rv64ud-p-fdiv");
708 }
709
710 #[test]
711 fn rv64ud_p_fmadd() {
712 rv_test!("../test/rv64ud-p-fmadd");
713 }
714
715 #[test]
716 fn rv64ud_p_fmin() {
717 rv_test!("../test/rv64ud-p-fmin");
718 }
719
720 #[test]
721 fn rv64ud_p_ldst() {
722 rv_test!("../test/rv64ud-p-ldst");
723 }
724
725 #[test]
726 #[ignore]
727 fn rv64ud_p_move() {
728 rv_test!("../test/rv64ud-p-move");
729 }
730
731 #[test]
732 fn rv64ud_p_recoding() {
733 rv_test!("../test/rv64ud-p-recoding");
734 }
735
736 #[test]
737 fn rv64ud_p_structural() {
738 rv_test!("../test/rv64ud-p-structural");
739 }
740 }
741
742 mod examples {
743 use super::*;
744
745 #[test]
746 fn mandelbrot() {
747 rv_test!("../test/mandelbrot");
748 }
749
750 #[test]
751 fn mandelbrot_debug() {
752 rv_test!("../test/mandelbrot-debug");
753 }
754 }
755}