user_mode_riscv/
lib.rs

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            // let typ = TypeRela64::from(entry.get_type());
47            // let addr: *mut u64 = (self.vbase + entry.get_offset()) as *mut u64;
48
49            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            //println!("Loading region from {:#x} into {:?} with {:?} bytes", base, start, region.len());
58            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            // let tls_end = tdata_start +  total_size;
77            // println!("Initial TLS region is at = {:#x} -- {:#x}", tdata_start, tls_end);
78            //Ok(())
79
80            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(()), // WRITE
99                    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            // frcsr is a fake opcode
621            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}