├── .gitignore ├── src ├── lib.rs ├── rv │ ├── mod.rs │ ├── args.rs │ ├── disas_helper.rs │ ├── insn.rs │ └── rvc.rs ├── bin │ ├── larva-disas │ │ └── main.rs │ └── larva-test │ │ └── main.rs └── exec │ ├── mod.rs │ ├── interp │ ├── syscall.rs │ └── mod.rs │ └── mem.rs ├── Cargo.toml ├── README.md ├── Cargo.lock ├── docs └── design.md └── COPYING /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod exec; 2 | pub mod rv; 3 | -------------------------------------------------------------------------------- /src/rv/mod.rs: -------------------------------------------------------------------------------- 1 | mod args; 2 | mod disas_helper; 3 | mod insn; 4 | mod rvc; 5 | 6 | pub use args::*; 7 | pub use insn::{RvDecoder, RvInsn}; 8 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "larva" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | libc = "*" 10 | memmap = "*" 11 | -------------------------------------------------------------------------------- /src/bin/larva-disas/main.rs: -------------------------------------------------------------------------------- 1 | use larva::rv::RvDecoder; 2 | 3 | fn main() { 4 | let argv = std::env::args(); 5 | for input_path in argv.skip(1) { 6 | process(&input_path); 7 | } 8 | } 9 | 10 | fn process(input_path: &str) { 11 | let mem = std::fs::read(input_path).unwrap(); 12 | 13 | let d = RvDecoder::new(64); 14 | let mut p = 0; 15 | loop { 16 | if let Some((insn, size)) = d.disas(&mem[p..mem.len()]) { 17 | println!("{:16x}: {:?}", p, insn); 18 | p += size; 19 | } else { 20 | break; 21 | } 22 | 23 | if p == mem.len() { 24 | break; 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # LARVa - Bridging LoongArch to RISC-V 2 | 3 | This project is a proof-of-concept RISC-V emulator aiming at near-native 4 | execution performance on LoongArch. 5 | Support may expand to other architectures in the future, if the techniques 6 | employed here prove useful and reasonably arch-independent. 7 | 8 | The project is named after a popular but extremely difficult chart with the 9 | same name, in the rhythm game *maimai*. Binary translation is hard, running such 10 | logic in privileged mode is even harder; while I cannot play the *maimai* 11 | chart at all, I do hope to manage the difficulty *here* somehow! 12 | 13 | ## License 14 | 15 | [GPL-3.0-or-later](https://spdx.org/licenses/GPL-3.0-or-later.html) 16 | 17 | ## Roadmap 18 | 19 | * [x] RV64GC disassembly 20 | * [ ] verification interpreter -- WIP 21 | * [ ] emulation machinery 22 | * [x] guest MMU -- barebones 23 | * [ ] linux-user emulation 24 | * [x] stack -- works okay 25 | * [ ] thread-local storage 26 | * [ ] syscalls -- WIP, only `exit_group` so far 27 | * [ ] LoongArch assembly 28 | * [ ] translation passes 29 | * [ ] system level PoC 30 | - TODO 31 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "larva" 7 | version = "0.1.0" 8 | dependencies = [ 9 | "libc", 10 | "memmap", 11 | ] 12 | 13 | [[package]] 14 | name = "libc" 15 | version = "0.2.150" 16 | source = "registry+https://github.com/rust-lang/crates.io-index" 17 | checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" 18 | 19 | [[package]] 20 | name = "memmap" 21 | version = "0.7.0" 22 | source = "registry+https://github.com/rust-lang/crates.io-index" 23 | checksum = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b" 24 | dependencies = [ 25 | "libc", 26 | "winapi", 27 | ] 28 | 29 | [[package]] 30 | name = "winapi" 31 | version = "0.3.9" 32 | source = "registry+https://github.com/rust-lang/crates.io-index" 33 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 34 | dependencies = [ 35 | "winapi-i686-pc-windows-gnu", 36 | "winapi-x86_64-pc-windows-gnu", 37 | ] 38 | 39 | [[package]] 40 | name = "winapi-i686-pc-windows-gnu" 41 | version = "0.4.0" 42 | source = "registry+https://github.com/rust-lang/crates.io-index" 43 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 44 | 45 | [[package]] 46 | name = "winapi-x86_64-pc-windows-gnu" 47 | version = "0.4.0" 48 | source = "registry+https://github.com/rust-lang/crates.io-index" 49 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 50 | -------------------------------------------------------------------------------- /src/exec/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod interp; 2 | pub mod mem; 3 | 4 | #[derive(Debug)] 5 | pub enum StopReason { 6 | Next, 7 | ContinueAt(u64), 8 | 9 | Break, 10 | ReservedInsn, 11 | Segv { read: bool, gaddr: u64 }, 12 | } 13 | 14 | #[derive(PartialEq, Debug, Default)] 15 | pub struct RvIsaState { 16 | pc: u64, 17 | regs_x: [u64; 31], 18 | regs_f: [u64; 32], 19 | } 20 | 21 | impl RvIsaState { 22 | pub fn get_pc(&self) -> u64 { 23 | self.pc 24 | } 25 | 26 | pub fn set_pc(&mut self, val: u64) { 27 | self.pc = val; 28 | } 29 | 30 | pub fn get_x(&self, idx: u8) -> u64 { 31 | debug_assert!(idx < 32); 32 | if idx == 0 { 33 | 0 34 | } else { 35 | self.regs_x[idx as usize - 1] 36 | } 37 | } 38 | 39 | pub fn set_x(&mut self, idx: u8, val: u64) { 40 | debug_assert!(idx < 32); 41 | if idx == 0 { 42 | return; 43 | } 44 | self.regs_x[idx as usize - 1] = val; 45 | } 46 | 47 | pub fn get_f32(&self, idx: u8) -> f32 { 48 | debug_assert!(idx < 32); 49 | self.regs_f[idx as usize] as u32 as f32 50 | } 51 | 52 | pub fn set_f32(&mut self, idx: u8, val: f32) { 53 | debug_assert!(idx < 32); 54 | self.regs_f[idx as usize] = val as i32 as i64 as u64; 55 | } 56 | 57 | pub fn get_f64(&self, idx: u8) -> f64 { 58 | debug_assert!(idx < 32); 59 | self.regs_f[idx as usize] as f64 60 | } 61 | 62 | pub fn set_f64(&mut self, idx: u8, val: f64) { 63 | debug_assert!(idx < 32); 64 | self.regs_f[idx as usize] = val as u64; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/exec/interp/syscall.rs: -------------------------------------------------------------------------------- 1 | use libc; 2 | 3 | use super::{RvInterpreterExecutor, StopReason}; 4 | 5 | impl<'a> RvInterpreterExecutor<'a> { 6 | pub(super) fn do_syscall(&mut self) -> StopReason { 7 | let nr = self.state.get_x(17); // a7 8 | let arg0 = self.state.get_x(10); // a0 9 | let arg1 = self.state.get_x(11); // a1 10 | let arg2 = self.state.get_x(12); // a2 11 | let arg3 = self.state.get_x(13); // a3 12 | let arg4 = self.state.get_x(14); // a4 13 | let arg5 = self.state.get_x(15); // a5 14 | 15 | if self.debug { 16 | println!( 17 | "syscall: {} ({:#x}, {:#x}, {:#x}, {:#x}, {:#x}, {:#x})", 18 | nr, arg0, arg1, arg2, arg3, arg4, arg5 19 | ); 20 | } 21 | match nr { 22 | 64 => self.do_sys_3args(libc::SYS_write, arg0, arg1, arg2), 23 | // exit_group 24 | 93 => self.do_sys_exit_group(arg0), 25 | 26 | _ => { 27 | println!( 28 | "unimplemented syscall: {} ({:#x}, {:#x}, {:#x}, {:#x}, {:#x}, {:#x})", 29 | nr, arg0, arg1, arg2, arg3, arg4, arg5 30 | ); 31 | self.state.set_x(10, u64::wrapping_neg(38)); // -ENOSYS 32 | StopReason::Next 33 | } 34 | } 35 | } 36 | 37 | fn do_sys_exit_group(&mut self, exitcode: u64) -> ! { 38 | unsafe { 39 | libc::syscall(libc::SYS_exit_group, exitcode as i64); 40 | } 41 | unreachable!(); 42 | } 43 | 44 | fn do_sys_3args(&mut self, nr: i64, arg0: u64, arg1: u64, arg2: u64) -> StopReason { 45 | let ret = unsafe { libc::syscall(nr, arg0, arg1, arg2) }; 46 | self.sx(10, ret as u64); 47 | StopReason::Next 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/bin/larva-test/main.rs: -------------------------------------------------------------------------------- 1 | use larva::exec; 2 | 3 | fn main() { 4 | /* 5 | 00000000000100b0 <_start>: 6 | 100b0: 4505 li a0,1 7 | 100b2: 00000597 auipc a1,0x0 8 | 100b6: 01e58593 addi a1,a1,30 # 100d0 9 | 100ba: 4631 li a2,12 10 | 100bc: 04000893 li a7,64 11 | 100c0: 00000073 ecall 12 | 100c4: 00000513 li a0,0 13 | 100c8: 05d00893 li a7,93 14 | 100cc: 00000073 ecall 15 | 16 | 00000000000100d0 : 17 | 100d0: 6c6c6568 .word 0x6c6c6568 18 | 100d4: 6f77206f .word 0x6f77206f 19 | 100d8: 0a646c72 .word 0x0a646c72 20 | */ 21 | let mem: [u8; 44] = [ 22 | 0x05, 0x45, 0x97, 0x05, 0x00, 0x00, 0x93, 0x85, 0xe5, 0x01, 0x31, 0x46, 0x93, 0x08, 0x00, 23 | 0x04, 0x73, 0x00, 0x00, 0x00, 0x13, 0x05, 0x00, 0x00, 0x93, 0x08, 0xd0, 0x05, 0x73, 0x00, 24 | 0x00, 0x00, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x0a, 25 | ]; 26 | 27 | let mut state = exec::RvIsaState::default(); 28 | 29 | // init MMU, consume the code block 30 | let mut mmu = exec::mem::GuestMmu::new(4096); // RV uses 4K pages 31 | mmu.consume_host(mem.as_ptr(), mem.len()).unwrap(); 32 | 33 | let mut executor = exec::interp::RvInterpreterExecutor::new(64, &mut state, &mut mmu); 34 | executor.stack(4096).unwrap(); 35 | 36 | let block_addr = mem.as_ptr() as u64; 37 | let entry_pc = block_addr + 0; 38 | println!("code addr = {:016x}", block_addr); 39 | println!(" entry pc = {:016x}", entry_pc); 40 | let exit_reason = executor.exec(entry_pc); 41 | println!("exit_reason = {:?}", exit_reason); 42 | } 43 | -------------------------------------------------------------------------------- /src/rv/args.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug)] 2 | pub struct RTypeArgs { 3 | pub rd: u8, 4 | pub rs1: u8, 5 | pub rs2: u8, 6 | } 7 | 8 | #[derive(Debug)] 9 | pub struct ITypeArgs { 10 | pub rd: u8, 11 | pub rs1: u8, 12 | pub imm: i32, 13 | } 14 | 15 | #[derive(Debug)] 16 | pub struct SBTypeArgs { 17 | pub rs1: u8, 18 | pub rs2: u8, 19 | pub imm: i32, 20 | } 21 | 22 | #[derive(Debug)] 23 | pub struct UJTypeArgs { 24 | pub rd: u8, 25 | pub imm: i32, 26 | } 27 | 28 | // variant of RTypeArgs 29 | #[derive(Debug)] 30 | pub struct ShiftArgs { 31 | pub rd: u8, 32 | pub rs1: u8, 33 | pub shamt: u8, 34 | } 35 | 36 | // variant of RTypeArgs 37 | #[derive(Debug)] 38 | pub struct AmoArgs { 39 | pub aq: bool, 40 | pub rl: bool, 41 | pub rd: u8, 42 | pub rs1: u8, 43 | pub rs2: u8, 44 | } 45 | 46 | // variant of RTypeArgs 47 | #[derive(Debug)] 48 | pub struct AmoLrArgs { 49 | pub aq: bool, 50 | pub rl: bool, 51 | pub rd: u8, 52 | pub rs1: u8, 53 | } 54 | 55 | #[derive(Debug)] 56 | pub struct FenceSet { 57 | pub i: bool, 58 | pub o: bool, 59 | pub r: bool, 60 | pub w: bool, 61 | } 62 | 63 | impl From for FenceSet { 64 | fn from(x: u8) -> Self { 65 | Self { 66 | i: x & 0b1000 != 0, 67 | o: x & 0b0100 != 0, 68 | r: x & 0b0010 != 0, 69 | w: x & 0b0001 != 0, 70 | } 71 | } 72 | } 73 | 74 | // variant of ITypeArgs 75 | #[derive(Debug)] 76 | pub struct FenceArgs { 77 | pub fm: u8, 78 | pub pred: FenceSet, 79 | pub succ: FenceSet, 80 | } 81 | 82 | #[derive(Debug)] 83 | pub enum RoundingMode { 84 | Rne, 85 | Rtz, 86 | Rdn, 87 | Rup, 88 | Rmm, 89 | Dyn, 90 | Reserved(u8), 91 | } 92 | 93 | impl From for RoundingMode { 94 | fn from(x: u8) -> Self { 95 | match x { 96 | 0b000 => Self::Rne, 97 | 0b001 => Self::Rtz, 98 | 0b010 => Self::Rdn, 99 | 0b011 => Self::Rup, 100 | 0b100 => Self::Rmm, 101 | 0b111 => Self::Dyn, 102 | _ => Self::Reserved(x), 103 | } 104 | } 105 | } 106 | 107 | #[derive(Debug)] 108 | pub struct R4TypeArgs { 109 | pub rm: RoundingMode, 110 | pub rd: u8, 111 | pub rs1: u8, 112 | pub rs2: u8, 113 | pub rs3: u8, 114 | } 115 | 116 | // variant of RTypeArgs 117 | #[derive(Debug)] 118 | pub struct RFTypeArgs { 119 | pub rm: RoundingMode, 120 | pub rd: u8, 121 | pub rs1: u8, 122 | pub rs2: u8, 123 | } 124 | 125 | // variant of RTypeArgs 126 | #[derive(Debug)] 127 | pub struct R2TypeArgs { 128 | pub rd: u8, 129 | pub rs1: u8, 130 | } 131 | 132 | // variant of RTypeArgs 133 | #[derive(Debug)] 134 | pub struct R2FTypeArgs { 135 | pub rm: RoundingMode, 136 | pub rd: u8, 137 | pub rs1: u8, 138 | } 139 | -------------------------------------------------------------------------------- /docs/design.md: -------------------------------------------------------------------------------- 1 | # LARVa Design Sketches 2 | 3 | For performance, the translation should be mostly one-pass, except for some 4 | beneficial "macro-op fusion" peephole optimizations. Regalloc is necessary 5 | though, and some kind of address space manipulation is also needed for 6 | transparency of emulation. 7 | 8 | ## User-mode insn correspondence 9 | 10 | These are nearly 1:1, which is extremely convenient. 11 | 12 | We model an RV64GC core, so XLEN=64 is assumed for native-width insns below. 13 | 14 | |RV Privileged|LA64| 15 | |:------------|:---| 16 | |`ecall`|`syscall`| 17 | 18 | |RV32I|LA64| 19 | |:----|:---| 20 | |`lui`|`lu12i.w`| 21 | |`auipc`|`pcaddu12i`| 22 | |`jal`|`jirl`?| 23 | |`jalr`|`jirl`| 24 | |`beq`|`beq`| 25 | |`bne`|`bne`| 26 | |`blt`|`bgt`| 27 | |`bge`|`ble`| 28 | |`bltu`|`bgtu`| 29 | |`bgeu`|`bleu`| 30 | |`lb`|`ld.b`| 31 | |`lh`|`ld.h`| 32 | |`lw`|`ld.w`| 33 | |`lbu`|`ld.bu`| 34 | |`lhu`|`ld.hu`| 35 | |`sb`|`st.b`| 36 | |`sh`|`st.h`| 37 | |`sw`|`st.w`| 38 | |`addi`|`addi.d`| 39 | |`slti`|`slti`| 40 | |`sltiu`|`sltui`| 41 | |`xori`|`xori`| 42 | |`ori`|`ori`| 43 | |`andi`|`andi`| 44 | |`slli`|`slli.d`| 45 | |`srli`|`srli.d`| 46 | |`srai`|`srai.d`| 47 | |`add`|`add.d`| 48 | |`sub`|`sub.d`| 49 | |`sll`|`sll.d`| 50 | |`slt`|`slt`| 51 | |`sltu`|`sltu`| 52 | |`xor`|`xor`| 53 | |`srl`|`srl.d`| 54 | |`sra`|`sra.d`| 55 | |`or`|`or`| 56 | |`and`|`and`| 57 | |`fence`|`dbar`| 58 | |`fence_i`|`ibar`| 59 | |`csrrw`|TODO| 60 | |`csrrs`|TODO| 61 | |`csrrc`|TODO| 62 | |`csrrwi`|TODO| 63 | |`csrrsi`|TODO| 64 | |`csrrci`|TODO| 65 | 66 | Only `dbar 0` is available on LA64 v1.00, but finer-grained barriers should 67 | appear in the next revision (and Loongson 3A6000). 68 | 69 | |RV64I|LA64| 70 | |:----|:---| 71 | |`lwu`|`ld.wu`| 72 | |`ld`|`ld.d`| 73 | |`sd`|`st.d`| 74 | |`addiw`|`add.w`| 75 | |`slliw`|`slli.w`| 76 | |`srliw`|`srli.w`| 77 | |`sraiw`|`srai.w`| 78 | |`addw`|`add.w`| 79 | |`subw`|`sub.w`| 80 | |`sllw`|`sll.w`| 81 | |`srlw`|`srl.w`| 82 | |`sraw`|`sra.w`| 83 | 84 | |RV32M|LA64| 85 | |:----|:---| 86 | |`mul`|`mul.d`| 87 | |`mulh`|`mulh.d`| 88 | |`mulhsu`|X| 89 | |`mulhu`|`mulh.du`| 90 | |`div`|`div.d`| 91 | |`divu`|`div.du`| 92 | |`rem`|`mod.d`| 93 | |`remu`|`mod.du`| 94 | 95 | `mulhsu` multiplies a signed value by an unsigned value, which has no direct 96 | LA64 correspondence. 97 | 98 | |RV64M|LA64| 99 | |:----|:---| 100 | |`mulw`|`mul.w`| 101 | |`divw`|`div.w`| 102 | |`divuw`|`div.wu`| 103 | |`remw`|`mod.w`| 104 | |`remuw`|`mod.wu`| 105 | 106 | |RV32A|LA64| 107 | |:----|:---| 108 | |`lr_w`|`ll.w`| 109 | |`sc_w`|`sc.w`| 110 | |`amoswap_w`|`amswap.w`| 111 | |`amoadd_w`|`amadd.w`| 112 | |`amoxor_w`|`amxor.w`| 113 | |`amoand_w`|`amand.w`| 114 | |`amoor_w`|`amor.w`| 115 | |`amomin_w`|`ammin.w`| 116 | |`amomax_w`|`ammax.w`| 117 | |`amominu_w`|`ammin.wu`| 118 | |`amomaxu_w`|`ammax.wu`| 119 | 120 | |RV64A|LA64| 121 | |:----|:---| 122 | |`lr_d`|`ll.d`| 123 | |`sc_d`|`sc.d`| 124 | |`amoswap_d`|`amswap.d`| 125 | |`amoadd_d`|`amadd.d`| 126 | |`amoxor_d`|`amxor.d`| 127 | |`amoand_d`|`amand.d`| 128 | |`amoor_d`|`amor.d`| 129 | |`amomin_d`|`ammin.d`| 130 | |`amomax_d`|`ammax.d`| 131 | |`amominu_d`|`ammin.du`| 132 | |`amomaxu_d`|`ammax.du`| 133 | 134 | RVF and RVD correspondences: TODO 135 | -------------------------------------------------------------------------------- /src/exec/mem.rs: -------------------------------------------------------------------------------- 1 | use std::{ 2 | collections::HashMap, 3 | ops::{Add, Sub}, 4 | }; 5 | 6 | use memmap; 7 | 8 | #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] 9 | pub struct HostAddr(u64); 10 | 11 | impl HostAddr { 12 | pub fn as_u64(&self) -> u64 { 13 | self.0 14 | } 15 | } 16 | 17 | #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] 18 | pub struct GuestAddr(u64); 19 | 20 | impl GuestAddr { 21 | pub fn as_u64(&self) -> u64 { 22 | self.0 23 | } 24 | } 25 | 26 | impl From for u64 { 27 | fn from(x: GuestAddr) -> Self { 28 | x.0 29 | } 30 | } 31 | 32 | impl From for GuestAddr { 33 | fn from(x: u64) -> Self { 34 | Self(x) 35 | } 36 | } 37 | 38 | impl Add for GuestAddr { 39 | type Output = Self; 40 | 41 | fn add(self, rhs: usize) -> Self { 42 | Self(self.0 + rhs as u64) 43 | } 44 | } 45 | 46 | impl Sub for GuestAddr { 47 | type Output = usize; 48 | 49 | fn sub(self, rhs: GuestAddr) -> Self::Output { 50 | (self.0 - rhs.0) as usize 51 | } 52 | } 53 | 54 | fn host_page_size() -> usize { 55 | unsafe { ::libc::sysconf(::libc::_SC_PAGESIZE) as usize } 56 | } 57 | 58 | fn get_page_shift(page_size: usize) -> usize { 59 | // only common sizes 60 | match page_size { 61 | 1024 => 10, 62 | 2048 => 11, 63 | 4096 => 12, 64 | 8192 => 13, 65 | 16384 => 14, 66 | 32768 => 15, 67 | 65536 => 16, 68 | 131072 => 17, 69 | 262144 => 18, 70 | 524288 => 19, 71 | 1048576 => 20, 72 | _ => unimplemented!(), 73 | } 74 | } 75 | 76 | fn align_to_page(len: usize, page_size: usize, page_shift: usize) -> usize { 77 | if len % page_size == 0 { 78 | len 79 | } else { 80 | (len >> page_shift + 1) << page_shift 81 | } 82 | } 83 | 84 | enum MemBlock { 85 | Map(memmap::MmapMut), 86 | Injected { _p: *const u8, len: usize }, 87 | InjectedMut { _p: *mut u8, len: usize }, 88 | } 89 | 90 | impl MemBlock { 91 | fn len(&self) -> usize { 92 | match self { 93 | MemBlock::Map(x) => x.len(), 94 | MemBlock::Injected { _p: _, len } => *len, 95 | MemBlock::InjectedMut { _p: _, len } => *len, 96 | } 97 | } 98 | } 99 | 100 | /// Naïve implementation of an MMU. 101 | pub struct GuestMmu { 102 | guest_page_size: usize, 103 | guest_page_shift: usize, 104 | host_page_size: usize, 105 | host_page_shift: usize, 106 | maps: std::sync::RwLock>, 107 | } 108 | impl GuestMmu { 109 | pub fn new(guest_page_size: usize) -> Self { 110 | let host_page_size = host_page_size(); 111 | Self { 112 | guest_page_size, 113 | guest_page_shift: get_page_shift(guest_page_size), 114 | host_page_size, 115 | host_page_shift: get_page_shift(host_page_size), 116 | maps: std::sync::RwLock::new(HashMap::new()), 117 | } 118 | } 119 | 120 | pub fn consume_host(&mut self, mem: *const u8, len: usize) -> ::std::io::Result { 121 | let m = MemBlock::Injected { _p: mem, len: len }; 122 | let addr = mem as u64; 123 | 124 | let mut maps = self.maps.write().unwrap(); 125 | maps.insert(addr.into(), m); 126 | 127 | Ok(addr.into()) 128 | } 129 | 130 | pub fn consume_host_mut(&mut self, mem: *mut u8, len: usize) -> ::std::io::Result { 131 | let m = MemBlock::InjectedMut { _p: mem, len: len }; 132 | let addr = mem as u64; 133 | 134 | let mut maps = self.maps.write().unwrap(); 135 | maps.insert(addr.into(), m); 136 | 137 | Ok(addr.into()) 138 | } 139 | 140 | // Naïve implementation; doesn't support fixed maps nor file-backed maps. 141 | pub fn mmap(&mut self, len: usize, stack: bool) -> ::std::io::Result { 142 | if len == 0 { 143 | return Err(std::io::ErrorKind::InvalidInput.into()); 144 | } 145 | 146 | // align to host page only if host page size is bigger than guest's, 147 | // else align to guest page 148 | let len = if self.host_page_size > self.guest_page_size { 149 | align_to_page(len, self.host_page_size, self.host_page_shift) 150 | } else { 151 | align_to_page(len, self.guest_page_size, self.guest_page_shift) 152 | }; 153 | 154 | let mut maps = self.maps.write().unwrap(); 155 | 156 | let mut m = memmap::MmapOptions::new(); 157 | m.len(len); 158 | if stack { 159 | m.stack(); 160 | } 161 | 162 | let m = m.map_anon()?; 163 | let addr = m.as_ptr() as u64; 164 | maps.insert(addr.into(), MemBlock::Map(m)); 165 | 166 | Ok(addr.into()) 167 | } 168 | 169 | pub fn munmap(&mut self, g: GuestAddr, len: usize) { 170 | let mut maps = self.maps.write().unwrap(); 171 | maps.retain(|g_start, m| { 172 | // check for intersection 173 | // [g, g + len) vs [g_start, g_start + m.len()) 174 | // only keep those ranges NOT overlapping the requested range 175 | (g + len) <= *g_start || (*g_start + m.len()) <= g 176 | }); 177 | } 178 | 179 | pub fn g2h(&self, g: GuestAddr) -> Option { 180 | let maps = self.maps.read().unwrap(); 181 | for (g_start, m) in maps.iter() { 182 | if g < *g_start { 183 | continue; 184 | } 185 | 186 | let offset = g - *g_start; 187 | if offset < m.len() { 188 | return Some(HostAddr(g.0)); 189 | } 190 | } 191 | 192 | None 193 | } 194 | } 195 | -------------------------------------------------------------------------------- /src/rv/disas_helper.rs: -------------------------------------------------------------------------------- 1 | use super::args::*; 2 | 3 | // funct7, rs2, rs1, funct3, rd 4 | pub(super) struct RTypeSlots(u8, u8, u8, u8, u8); 5 | 6 | impl RTypeSlots { 7 | pub(super) fn funct7(&self) -> u8 { 8 | self.0 9 | } 10 | 11 | pub(super) fn funct3(&self) -> u8 { 12 | self.3 13 | } 14 | 15 | pub(super) fn rs2(&self) -> u8 { 16 | self.1 17 | } 18 | 19 | pub(super) fn amo_funct(&self) -> u8 { 20 | self.funct7() >> 2 21 | } 22 | 23 | pub(super) fn amo_aq(&self) -> bool { 24 | self.funct7() & 0b10 != 0 25 | } 26 | 27 | pub(super) fn amo_rl(&self) -> bool { 28 | self.funct7() & 0b01 != 0 29 | } 30 | } 31 | 32 | impl From for RTypeArgs { 33 | fn from(x: RTypeSlots) -> Self { 34 | Self { 35 | rd: x.4, 36 | rs1: x.2, 37 | rs2: x.1, 38 | } 39 | } 40 | } 41 | 42 | impl From for AmoArgs { 43 | fn from(x: RTypeSlots) -> Self { 44 | Self { 45 | aq: x.amo_aq(), 46 | rl: x.amo_rl(), 47 | rd: x.4, 48 | rs1: x.2, 49 | rs2: x.1, 50 | } 51 | } 52 | } 53 | 54 | impl From for AmoLrArgs { 55 | fn from(x: RTypeSlots) -> Self { 56 | Self { 57 | aq: x.amo_aq(), 58 | rl: x.amo_rl(), 59 | rd: x.4, 60 | rs1: x.2, 61 | } 62 | } 63 | } 64 | 65 | impl From for RFTypeArgs { 66 | fn from(x: RTypeSlots) -> Self { 67 | Self { 68 | rm: x.funct3().into(), 69 | rd: x.4, 70 | rs1: x.2, 71 | rs2: x.1, 72 | } 73 | } 74 | } 75 | 76 | impl From for R2TypeArgs { 77 | fn from(x: RTypeSlots) -> Self { 78 | Self { rd: x.4, rs1: x.2 } 79 | } 80 | } 81 | 82 | impl From for R2FTypeArgs { 83 | fn from(x: RTypeSlots) -> Self { 84 | Self { 85 | rm: x.funct3().into(), 86 | rd: x.4, 87 | rs1: x.2, 88 | } 89 | } 90 | } 91 | 92 | // I-type: imm, rs1, funct3, rd 93 | // S-type & B-type: imm, rs2, rs1, funct3 94 | pub(super) struct ISBTypeSlots(i32, u8, u8, u8); 95 | 96 | impl ISBTypeSlots { 97 | pub(super) fn i_funct3(&self) -> u8 { 98 | self.2 99 | } 100 | 101 | pub(super) fn sb_funct3(&self) -> u8 { 102 | self.3 103 | } 104 | 105 | pub(super) fn rv32_shift_funct(&self) -> u8 { 106 | (self.0 >> 5) as u8 107 | } 108 | 109 | pub(super) fn rv64_shift_funct(&self) -> u8 { 110 | (self.0 >> 6) as u8 111 | } 112 | 113 | pub(super) fn fence_fm(&self) -> u8 { 114 | (self.0 >> 8) as u8 115 | } 116 | 117 | pub(super) fn fence_pred(&self) -> FenceSet { 118 | (((self.0 >> 4) & 0b1111) as u8).into() 119 | } 120 | 121 | pub(super) fn fence_succ(&self) -> FenceSet { 122 | ((self.0 & 0b1111) as u8).into() 123 | } 124 | } 125 | 126 | impl From for ITypeArgs { 127 | fn from(x: ISBTypeSlots) -> Self { 128 | Self { 129 | rd: x.3, 130 | rs1: x.1, 131 | imm: x.0, 132 | } 133 | } 134 | } 135 | 136 | impl From for SBTypeArgs { 137 | fn from(x: ISBTypeSlots) -> Self { 138 | Self { 139 | rs1: x.2, 140 | rs2: x.1, 141 | imm: x.0, 142 | } 143 | } 144 | } 145 | 146 | impl From for ShiftArgs { 147 | fn from(x: ISBTypeSlots) -> Self { 148 | Self { 149 | rd: x.3, 150 | rs1: x.1, 151 | shamt: (x.0 & 0xff) as u8, 152 | } 153 | } 154 | } 155 | 156 | impl From for FenceArgs { 157 | fn from(x: ISBTypeSlots) -> Self { 158 | Self { 159 | fm: x.fence_fm(), 160 | pred: x.fence_pred(), 161 | succ: x.fence_succ(), 162 | } 163 | } 164 | } 165 | 166 | // U-type & J-type: imm, rd 167 | pub(super) struct UJTypeSlots(i32, u8); 168 | 169 | impl From for UJTypeArgs { 170 | fn from(x: UJTypeSlots) -> Self { 171 | Self { rd: x.1, imm: x.0 } 172 | } 173 | } 174 | 175 | // rs3, funct2, rs2, rs1, funct3, rd 176 | pub(super) struct R4TypeSlots(u8, u8, u8, u8, u8, u8); 177 | 178 | impl R4TypeSlots { 179 | pub(super) fn funct2(&self) -> u8 { 180 | self.1 181 | } 182 | } 183 | 184 | impl From for R4TypeArgs { 185 | fn from(x: R4TypeSlots) -> Self { 186 | Self { 187 | rm: x.4.into(), 188 | rd: x.5, 189 | rs1: x.3, 190 | rs2: x.2, 191 | rs3: x.0, 192 | } 193 | } 194 | } 195 | 196 | pub(super) fn simm_from_uimm(uimm: u32, width: u8) -> i32 { 197 | // example with width = 6, uimm = 0b100111: 198 | // 199 | // a = 1 << width = 0b1000000 200 | // b = a >> 1 = 0b100000 (sign bit) 201 | // uimm >= b, abs(simm) = a - uimm 202 | let a = 1 << width; 203 | let b = a >> 1; 204 | if uimm < b { 205 | uimm as i32 206 | } else { 207 | -((a - uimm) as i32) 208 | } 209 | } 210 | 211 | pub(super) fn disas_r(insn: u32) -> RTypeSlots { 212 | let funct7 = (insn >> 25) as u8; 213 | let rs2 = ((insn >> 20) & 0b11111) as u8; 214 | let rs1 = ((insn >> 15) & 0b11111) as u8; 215 | let funct3 = ((insn >> 12) & 0b111) as u8; 216 | let rd = ((insn >> 7) & 0b11111) as u8; 217 | RTypeSlots(funct7, rs2, rs1, funct3, rd) 218 | } 219 | 220 | pub(super) fn disas_i(insn: u32) -> ISBTypeSlots { 221 | let imm = simm_from_uimm(insn >> 20, 12); 222 | let rs1 = ((insn >> 15) & 0b11111) as u8; 223 | let funct3 = ((insn >> 12) & 0b111) as u8; 224 | let rd = ((insn >> 7) & 0b11111) as u8; 225 | ISBTypeSlots(imm, rs1, funct3, rd) 226 | } 227 | 228 | pub(super) fn disas_s(insn: u32) -> ISBTypeSlots { 229 | let imm = (insn >> (25 - 5)) | ((insn >> 7) & 0b11111); 230 | let imm = simm_from_uimm(imm, 12); 231 | let rs2 = ((insn >> 20) & 0b11111) as u8; 232 | let rs1 = ((insn >> 15) & 0b11111) as u8; 233 | let funct3 = ((insn >> 12) & 0b111) as u8; 234 | ISBTypeSlots(imm, rs2, rs1, funct3) 235 | } 236 | 237 | pub(super) fn disas_b(insn: u32) -> ISBTypeSlots { 238 | let imm = { 239 | let a = insn >> 31; 240 | let b = (insn >> 7) & 1; 241 | let c = (insn >> 25) & 0b111111; 242 | let d = (insn >> 8) & 0b1111; 243 | (a << 12) | (b << 11) | (c << 5) | (d << 1) 244 | }; 245 | let imm = simm_from_uimm(imm, 13); 246 | let rs2 = ((insn >> 20) & 0b11111) as u8; 247 | let rs1 = ((insn >> 15) & 0b11111) as u8; 248 | let funct3 = ((insn >> 12) & 0b111) as u8; 249 | ISBTypeSlots(imm, rs2, rs1, funct3) 250 | } 251 | 252 | pub(super) fn disas_u(insn: u32) -> UJTypeSlots { 253 | let imm = simm_from_uimm(insn >> 12, 20) << 12; 254 | let rd = ((insn >> 7) & 0b11111) as u8; 255 | UJTypeSlots(imm, rd) 256 | } 257 | 258 | pub(super) fn disas_j(insn: u32) -> UJTypeSlots { 259 | let imm = { 260 | let a = insn >> 31; 261 | let b = (insn >> 12) & 0b11111111; 262 | let c = (insn >> 20) & 1; 263 | let d = (insn >> 21) & 0b1111111111; 264 | (a << 20) | (b << 12) | (c << 11) | (d << 1) 265 | }; 266 | let imm = simm_from_uimm(imm, 21); 267 | let rd = ((insn >> 7) & 0b11111) as u8; 268 | UJTypeSlots(imm, rd) 269 | } 270 | 271 | pub(super) fn disas_r4(insn: u32) -> R4TypeSlots { 272 | let rs3 = (insn >> 27) as u8; 273 | let funct2 = ((insn >> 25) & 0b11) as u8; 274 | let rs2 = ((insn >> 20) & 0b11111) as u8; 275 | let rs1 = ((insn >> 15) & 0b11111) as u8; 276 | let funct3 = ((insn >> 12) & 0b111) as u8; 277 | let rd = ((insn >> 7) & 0b11111) as u8; 278 | R4TypeSlots(rs3, funct2, rs2, rs1, funct3, rd) 279 | } 280 | -------------------------------------------------------------------------------- /src/rv/insn.rs: -------------------------------------------------------------------------------- 1 | use super::args::*; 2 | use super::disas_helper::*; 3 | use super::rvc::RvCDecoder; 4 | 5 | #[derive(Debug)] 6 | pub enum RvInsn { 7 | // Invalid encoding 8 | Invalid(u32), 9 | 10 | // Privileged 11 | Ecall, 12 | Ebreak, 13 | 14 | // RV32I 15 | Lui(UJTypeArgs), 16 | Auipc(UJTypeArgs), 17 | Jal(UJTypeArgs), 18 | Jalr(ITypeArgs), 19 | Beq(SBTypeArgs), 20 | Bne(SBTypeArgs), 21 | Blt(SBTypeArgs), 22 | Bge(SBTypeArgs), 23 | Bltu(SBTypeArgs), 24 | Bgeu(SBTypeArgs), 25 | Lb(ITypeArgs), 26 | Lh(ITypeArgs), 27 | Lw(ITypeArgs), 28 | Lbu(ITypeArgs), 29 | Lhu(ITypeArgs), 30 | Sb(SBTypeArgs), 31 | Sh(SBTypeArgs), 32 | Sw(SBTypeArgs), 33 | Addi(ITypeArgs), 34 | Slti(ITypeArgs), 35 | Sltiu(ITypeArgs), 36 | Xori(ITypeArgs), 37 | Ori(ITypeArgs), 38 | Andi(ITypeArgs), 39 | Slli(ShiftArgs), 40 | Srli(ShiftArgs), 41 | Srai(ShiftArgs), 42 | Add(RTypeArgs), 43 | Sub(RTypeArgs), 44 | Sll(RTypeArgs), 45 | Slt(RTypeArgs), 46 | Sltu(RTypeArgs), 47 | Xor(RTypeArgs), 48 | Srl(RTypeArgs), 49 | Sra(RTypeArgs), 50 | Or(RTypeArgs), 51 | And(RTypeArgs), 52 | Fence(FenceArgs), 53 | 54 | // Zifencei 55 | FenceI(ITypeArgs), 56 | 57 | // RV64I 58 | Lwu(ITypeArgs), 59 | Ld(ITypeArgs), 60 | Sd(SBTypeArgs), 61 | Addiw(ITypeArgs), 62 | Slliw(ShiftArgs), 63 | Srliw(ShiftArgs), 64 | Sraiw(ShiftArgs), 65 | Addw(RTypeArgs), 66 | Subw(RTypeArgs), 67 | Sllw(RTypeArgs), 68 | Srlw(RTypeArgs), 69 | Sraw(RTypeArgs), 70 | 71 | // RV32M 72 | Mul(RTypeArgs), 73 | Mulh(RTypeArgs), 74 | Mulhsu(RTypeArgs), 75 | Mulhu(RTypeArgs), 76 | Div(RTypeArgs), 77 | Divu(RTypeArgs), 78 | Rem(RTypeArgs), 79 | Remu(RTypeArgs), 80 | 81 | // RV64M 82 | Mulw(RTypeArgs), 83 | Divw(RTypeArgs), 84 | Divuw(RTypeArgs), 85 | Remw(RTypeArgs), 86 | Remuw(RTypeArgs), 87 | 88 | // RV32A 89 | LrW(AmoLrArgs), 90 | ScW(AmoArgs), 91 | AmoSwapW(AmoArgs), 92 | AmoAddW(AmoArgs), 93 | AmoXorW(AmoArgs), 94 | AmoAndW(AmoArgs), 95 | AmoOrW(AmoArgs), 96 | AmoMinW(AmoArgs), 97 | AmoMaxW(AmoArgs), 98 | AmoMinuW(AmoArgs), 99 | AmoMaxuW(AmoArgs), 100 | 101 | // RV64A 102 | LrD(AmoLrArgs), 103 | ScD(AmoArgs), 104 | AmoSwapD(AmoArgs), 105 | AmoAddD(AmoArgs), 106 | AmoXorD(AmoArgs), 107 | AmoAndD(AmoArgs), 108 | AmoOrD(AmoArgs), 109 | AmoMinD(AmoArgs), 110 | AmoMaxD(AmoArgs), 111 | AmoMinuD(AmoArgs), 112 | AmoMaxuD(AmoArgs), 113 | 114 | // RV32F 115 | Flw(ITypeArgs), 116 | Fsw(SBTypeArgs), 117 | FmaddS(R4TypeArgs), 118 | FmsubS(R4TypeArgs), 119 | FnmsubS(R4TypeArgs), 120 | FnmaddS(R4TypeArgs), 121 | FaddS(RFTypeArgs), 122 | FsubS(RFTypeArgs), 123 | FmulS(RFTypeArgs), 124 | FdivS(RFTypeArgs), 125 | FsqrtS(R2FTypeArgs), 126 | FsgnjS(RTypeArgs), 127 | FsgnjnS(RTypeArgs), 128 | FsgnjxS(RTypeArgs), 129 | FminS(RTypeArgs), 130 | FmaxS(RTypeArgs), 131 | FcvtWS(R2FTypeArgs), 132 | FcvtWuS(R2FTypeArgs), 133 | FmvXW(R2TypeArgs), 134 | FeqS(RTypeArgs), 135 | FltS(RTypeArgs), 136 | FleS(RTypeArgs), 137 | FclassS(R2TypeArgs), 138 | FcvtSW(R2FTypeArgs), 139 | FcvtSWu(R2FTypeArgs), 140 | FmvWX(R2TypeArgs), 141 | 142 | // RV64F 143 | FcvtLS(R2FTypeArgs), 144 | FcvtLuS(R2FTypeArgs), 145 | FcvtSL(R2FTypeArgs), 146 | FcvtSLu(R2FTypeArgs), 147 | 148 | // RV32D 149 | Fld(ITypeArgs), 150 | Fsd(SBTypeArgs), 151 | FmaddD(R4TypeArgs), 152 | FmsubD(R4TypeArgs), 153 | FnmsubD(R4TypeArgs), 154 | FnmaddD(R4TypeArgs), 155 | FaddD(RFTypeArgs), 156 | FsubD(RFTypeArgs), 157 | FmulD(RFTypeArgs), 158 | FdivD(RFTypeArgs), 159 | FsqrtD(R2FTypeArgs), 160 | FsgnjD(RTypeArgs), 161 | FsgnjnD(RTypeArgs), 162 | FsgnjxD(RTypeArgs), 163 | FminD(RTypeArgs), 164 | FmaxD(RTypeArgs), 165 | FcvtSD(R2FTypeArgs), 166 | FcvtDS(R2FTypeArgs), 167 | FeqD(RTypeArgs), 168 | FltD(RTypeArgs), 169 | FleD(RTypeArgs), 170 | FclassD(R2TypeArgs), 171 | FcvtWD(R2FTypeArgs), 172 | FcvtWuD(R2FTypeArgs), 173 | FcvtDW(R2FTypeArgs), 174 | FcvtDWu(R2FTypeArgs), 175 | 176 | // RV64D 177 | FcvtLD(R2FTypeArgs), 178 | FcvtLuD(R2FTypeArgs), 179 | FmvXD(R2TypeArgs), 180 | FcvtDL(R2FTypeArgs), 181 | FcvtDLu(R2FTypeArgs), 182 | FmvDX(R2TypeArgs), 183 | } 184 | 185 | pub struct RvDecoder { 186 | rvc: RvCDecoder, 187 | } 188 | 189 | impl RvDecoder { 190 | pub fn new(xlen: usize) -> Self { 191 | Self { 192 | rvc: RvCDecoder::new(xlen), 193 | } 194 | } 195 | 196 | /// Decodes one RV instruction. Returns the decoded instruction and the 197 | /// instruction length in bytes. 198 | pub fn disas(&self, mem: &[u8]) -> Option<(RvInsn, usize)> { 199 | let quadrant = mem[0] & 0b11; 200 | if quadrant != 0b11 { 201 | // RVC insn. 202 | if mem.len() < 2 { 203 | None 204 | } else { 205 | let insn = (mem[1] as u16) << 8 | (mem[0] as u16); 206 | Some((self.rvc.disas(insn).into(), 2)) 207 | } 208 | } else { 209 | if mem.len() < 4 { 210 | None 211 | } else { 212 | let insn = (mem[3] as u32) << 24 213 | | (mem[2] as u32) << 16 214 | | (mem[1] as u32) << 8 215 | | (mem[0] as u32); 216 | Some((disas_32bit(insn), 4)) 217 | } 218 | } 219 | } 220 | 221 | pub fn disas_16bit(&self, insn: u16) -> RvInsn { 222 | self.rvc.disas(insn).into() 223 | } 224 | 225 | pub fn disas_32bit(&self, insn: u32) -> RvInsn { 226 | disas_32bit(insn) 227 | } 228 | } 229 | 230 | fn disas_32bit(insn: u32) -> RvInsn { 231 | let opcode = (insn >> 2) & 0b11111; 232 | match opcode { 233 | 0b00_000 => disas_load(insn), 234 | 0b00_001 => disas_load_fp(insn), 235 | 0b00_011 => disas_misc_mem(insn), 236 | 0b00_100 => disas_op_imm(insn), 237 | 0b00_101 => RvInsn::Auipc(disas_u(insn).into()), 238 | 0b00_110 => disas_op_imm_32(insn), 239 | 0b01_000 => disas_store(insn), 240 | 0b01_001 => disas_store_fp(insn), 241 | 0b01_011 => disas_amo(insn), 242 | 0b01_100 => disas_op(insn), 243 | 0b01_101 => RvInsn::Lui(disas_u(insn).into()), 244 | 0b01_110 => disas_op_32(insn), 245 | 0b10_000 => disas_madd(insn), 246 | 0b10_001 => disas_msub(insn), 247 | 0b10_010 => disas_nmsub(insn), 248 | 0b10_011 => disas_nmadd(insn), 249 | 0b10_100 => disas_op_fp(insn), 250 | 0b11_000 => disas_branch(insn), 251 | 0b11_001 => disas_jalr(insn), 252 | 0b11_011 => RvInsn::Jal(disas_j(insn).into()), 253 | 0b11_100 => disas_system(insn), 254 | _ => RvInsn::Invalid(insn), 255 | } 256 | } 257 | 258 | fn disas_load(insn: u32) -> RvInsn { 259 | let s = disas_i(insn); 260 | match s.i_funct3() { 261 | 0b000 => RvInsn::Lb(s.into()), 262 | 0b001 => RvInsn::Lh(s.into()), 263 | 0b010 => RvInsn::Lw(s.into()), 264 | 0b100 => RvInsn::Lbu(s.into()), 265 | 0b101 => RvInsn::Lhu(s.into()), 266 | 267 | 0b110 => RvInsn::Lwu(s.into()), 268 | 0b011 => RvInsn::Ld(s.into()), 269 | 270 | _ => RvInsn::Invalid(insn), 271 | } 272 | } 273 | 274 | fn disas_load_fp(insn: u32) -> RvInsn { 275 | let s = disas_i(insn); 276 | match s.i_funct3() { 277 | 0b010 => RvInsn::Flw(s.into()), 278 | 0b011 => RvInsn::Fld(s.into()), 279 | _ => RvInsn::Invalid(insn), 280 | } 281 | } 282 | 283 | fn disas_misc_mem(insn: u32) -> RvInsn { 284 | let s = disas_i(insn); 285 | match s.i_funct3() { 286 | 0b000 => RvInsn::Fence(s.into()), 287 | 0b001 => RvInsn::FenceI(s.into()), 288 | _ => RvInsn::Invalid(insn), 289 | } 290 | } 291 | 292 | fn disas_op_imm(insn: u32) -> RvInsn { 293 | let s = disas_i(insn); 294 | match s.i_funct3() { 295 | 0b000 => RvInsn::Addi(s.into()), 296 | 0b010 => RvInsn::Slti(s.into()), 297 | 0b011 => RvInsn::Sltiu(s.into()), 298 | 0b100 => RvInsn::Xori(s.into()), 299 | 0b110 => RvInsn::Ori(s.into()), 300 | 0b111 => RvInsn::Andi(s.into()), 301 | 302 | 0b001 | 0b101 => match (s.rv64_shift_funct(), s.i_funct3()) { 303 | (0b000000, 0b001) => RvInsn::Slli(s.into()), 304 | (0b000000, 0b101) => RvInsn::Srli(s.into()), 305 | (0b010000, 0b101) => RvInsn::Srai(s.into()), 306 | _ => RvInsn::Invalid(insn), 307 | }, 308 | 309 | _ => RvInsn::Invalid(insn), 310 | } 311 | } 312 | 313 | fn disas_op_imm_32(insn: u32) -> RvInsn { 314 | let s = disas_i(insn); 315 | match (s.rv32_shift_funct(), s.i_funct3()) { 316 | (_, 0b000) => RvInsn::Addiw(s.into()), 317 | (0b0000000, 0b001) => RvInsn::Slliw(s.into()), 318 | (0b0000000, 0b101) => RvInsn::Srliw(s.into()), 319 | (0b0100000, 0b101) => RvInsn::Sraiw(s.into()), 320 | 321 | _ => RvInsn::Invalid(insn), 322 | } 323 | } 324 | 325 | fn disas_store(insn: u32) -> RvInsn { 326 | let s = disas_s(insn); 327 | match s.sb_funct3() { 328 | 0b000 => RvInsn::Sb(s.into()), 329 | 0b001 => RvInsn::Sh(s.into()), 330 | 0b010 => RvInsn::Sw(s.into()), 331 | 332 | 0b011 => RvInsn::Sd(s.into()), 333 | 334 | _ => RvInsn::Invalid(insn), 335 | } 336 | } 337 | 338 | fn disas_store_fp(insn: u32) -> RvInsn { 339 | let s = disas_s(insn); 340 | match s.sb_funct3() { 341 | 0b010 => RvInsn::Fsw(s.into()), 342 | 0b011 => RvInsn::Fsd(s.into()), 343 | _ => RvInsn::Invalid(insn), 344 | } 345 | } 346 | 347 | fn disas_amo(insn: u32) -> RvInsn { 348 | let s = disas_r(insn); 349 | match (s.funct3(), s.amo_funct()) { 350 | (0b010, 0b00010) => { 351 | if s.rs2() == 0 { 352 | RvInsn::LrW(s.into()) 353 | } else { 354 | RvInsn::Invalid(insn) 355 | } 356 | } 357 | (0b010, 0b00011) => RvInsn::ScW(s.into()), 358 | (0b010, 0b00001) => RvInsn::AmoSwapW(s.into()), 359 | (0b010, 0b00000) => RvInsn::AmoAddW(s.into()), 360 | (0b010, 0b00100) => RvInsn::AmoXorW(s.into()), 361 | (0b010, 0b01100) => RvInsn::AmoAndW(s.into()), 362 | (0b010, 0b01000) => RvInsn::AmoOrW(s.into()), 363 | (0b010, 0b10000) => RvInsn::AmoMinW(s.into()), 364 | (0b010, 0b10100) => RvInsn::AmoMaxW(s.into()), 365 | (0b010, 0b11000) => RvInsn::AmoMinuW(s.into()), 366 | (0b010, 0b11100) => RvInsn::AmoMaxuW(s.into()), 367 | 368 | (0b011, 0b00010) => { 369 | if s.rs2() == 0 { 370 | RvInsn::LrD(s.into()) 371 | } else { 372 | RvInsn::Invalid(insn) 373 | } 374 | } 375 | (0b011, 0b00011) => RvInsn::ScD(s.into()), 376 | (0b011, 0b00001) => RvInsn::AmoSwapD(s.into()), 377 | (0b011, 0b00000) => RvInsn::AmoAddD(s.into()), 378 | (0b011, 0b00100) => RvInsn::AmoXorD(s.into()), 379 | (0b011, 0b01100) => RvInsn::AmoAndD(s.into()), 380 | (0b011, 0b01000) => RvInsn::AmoOrD(s.into()), 381 | (0b011, 0b10000) => RvInsn::AmoMinD(s.into()), 382 | (0b011, 0b10100) => RvInsn::AmoMaxD(s.into()), 383 | (0b011, 0b11000) => RvInsn::AmoMinuD(s.into()), 384 | (0b011, 0b11100) => RvInsn::AmoMaxuD(s.into()), 385 | 386 | _ => RvInsn::Invalid(insn), 387 | } 388 | } 389 | 390 | fn disas_op(insn: u32) -> RvInsn { 391 | let s = disas_r(insn); 392 | match (s.funct7(), s.funct3()) { 393 | (0b0000000, 0b000) => RvInsn::Add(s.into()), 394 | (0b0100000, 0b000) => RvInsn::Sub(s.into()), 395 | (0b0000000, 0b001) => RvInsn::Sll(s.into()), 396 | (0b0000000, 0b010) => RvInsn::Slt(s.into()), 397 | (0b0000000, 0b011) => RvInsn::Sltu(s.into()), 398 | (0b0000000, 0b100) => RvInsn::Xor(s.into()), 399 | (0b0000000, 0b101) => RvInsn::Srl(s.into()), 400 | (0b0100000, 0b101) => RvInsn::Sra(s.into()), 401 | (0b0000000, 0b110) => RvInsn::Or(s.into()), 402 | (0b0000000, 0b111) => RvInsn::And(s.into()), 403 | 404 | (0b0000001, 0b000) => RvInsn::Mul(s.into()), 405 | (0b0000001, 0b001) => RvInsn::Mulh(s.into()), 406 | (0b0000001, 0b010) => RvInsn::Mulhsu(s.into()), 407 | (0b0000001, 0b011) => RvInsn::Mulhu(s.into()), 408 | (0b0000001, 0b100) => RvInsn::Div(s.into()), 409 | (0b0000001, 0b101) => RvInsn::Divu(s.into()), 410 | (0b0000001, 0b110) => RvInsn::Rem(s.into()), 411 | (0b0000001, 0b111) => RvInsn::Remu(s.into()), 412 | 413 | _ => RvInsn::Invalid(insn), 414 | } 415 | } 416 | 417 | fn disas_op_32(insn: u32) -> RvInsn { 418 | let s = disas_r(insn); 419 | match (s.funct7(), s.funct3()) { 420 | (0b0000000, 0b000) => RvInsn::Addw(s.into()), 421 | (0b0100000, 0b000) => RvInsn::Subw(s.into()), 422 | (0b0000000, 0b001) => RvInsn::Sllw(s.into()), 423 | (0b0000000, 0b101) => RvInsn::Srlw(s.into()), 424 | (0b0100000, 0b101) => RvInsn::Sraw(s.into()), 425 | 426 | (0b0000001, 0b000) => RvInsn::Mulw(s.into()), 427 | (0b0000001, 0b100) => RvInsn::Divw(s.into()), 428 | (0b0000001, 0b101) => RvInsn::Divuw(s.into()), 429 | (0b0000001, 0b110) => RvInsn::Remw(s.into()), 430 | (0b0000001, 0b111) => RvInsn::Remuw(s.into()), 431 | 432 | _ => RvInsn::Invalid(insn), 433 | } 434 | } 435 | 436 | fn disas_madd(insn: u32) -> RvInsn { 437 | let s = disas_r4(insn); 438 | match s.funct2() { 439 | 0b00 => RvInsn::FmaddS(s.into()), 440 | 0b01 => RvInsn::FmaddD(s.into()), 441 | _ => RvInsn::Invalid(insn), 442 | } 443 | } 444 | 445 | fn disas_msub(insn: u32) -> RvInsn { 446 | let s = disas_r4(insn); 447 | match s.funct2() { 448 | 0b00 => RvInsn::FmsubS(s.into()), 449 | 0b01 => RvInsn::FmsubD(s.into()), 450 | _ => RvInsn::Invalid(insn), 451 | } 452 | } 453 | 454 | fn disas_nmsub(insn: u32) -> RvInsn { 455 | let s = disas_r4(insn); 456 | match s.funct2() { 457 | 0b00 => RvInsn::FnmsubS(s.into()), 458 | 0b01 => RvInsn::FnmsubD(s.into()), 459 | _ => RvInsn::Invalid(insn), 460 | } 461 | } 462 | 463 | fn disas_nmadd(insn: u32) -> RvInsn { 464 | let s = disas_r4(insn); 465 | match s.funct2() { 466 | 0b00 => RvInsn::FnmaddS(s.into()), 467 | 0b01 => RvInsn::FnmaddD(s.into()), 468 | _ => RvInsn::Invalid(insn), 469 | } 470 | } 471 | 472 | fn disas_op_fp(insn: u32) -> RvInsn { 473 | let s = disas_r(insn); 474 | match (s.funct7(), s.rs2(), s.funct3()) { 475 | // RV32F 476 | (0b0000000, _, _) => RvInsn::FaddS(s.into()), 477 | (0b0000100, _, _) => RvInsn::FsubS(s.into()), 478 | (0b0001000, _, _) => RvInsn::FmulS(s.into()), 479 | (0b0001100, _, _) => RvInsn::FdivS(s.into()), 480 | (0b0101100, 0b00000, _) => RvInsn::FsqrtS(s.into()), 481 | (0b0010000, _, 0b000) => RvInsn::FsgnjS(s.into()), 482 | (0b0010000, _, 0b001) => RvInsn::FsgnjnS(s.into()), 483 | (0b0010000, _, 0b010) => RvInsn::FsgnjxS(s.into()), 484 | (0b0010100, _, 0b000) => RvInsn::FminS(s.into()), 485 | (0b0010100, _, 0b001) => RvInsn::FmaxS(s.into()), 486 | (0b1100000, 0b00000, _) => RvInsn::FcvtWS(s.into()), 487 | (0b1100000, 0b00001, _) => RvInsn::FcvtWuS(s.into()), 488 | (0b1110000, 0b00000, 0b000) => RvInsn::FmvXW(s.into()), 489 | (0b1010000, _, 0b010) => RvInsn::FeqS(s.into()), 490 | (0b1010000, _, 0b001) => RvInsn::FltS(s.into()), 491 | (0b1010000, _, 0b000) => RvInsn::FleS(s.into()), 492 | (0b1110000, 0b00000, 0b001) => RvInsn::FclassS(s.into()), 493 | (0b1101000, 0b00000, _) => RvInsn::FcvtSW(s.into()), 494 | (0b1101000, 0b00001, _) => RvInsn::FcvtSWu(s.into()), 495 | (0b1111000, 0b00000, 0b000) => RvInsn::FmvWX(s.into()), 496 | 497 | // RV64F 498 | (0b1100000, 0b00010, _) => RvInsn::FcvtLS(s.into()), 499 | (0b1100000, 0b00011, _) => RvInsn::FcvtLuS(s.into()), 500 | (0b1101000, 0b00010, _) => RvInsn::FcvtSL(s.into()), 501 | (0b1101000, 0b00011, _) => RvInsn::FcvtSLu(s.into()), 502 | 503 | // RV32D 504 | (0b0000001, _, _) => RvInsn::FaddD(s.into()), 505 | (0b0000101, _, _) => RvInsn::FsubD(s.into()), 506 | (0b0001001, _, _) => RvInsn::FmulD(s.into()), 507 | (0b0001101, _, _) => RvInsn::FdivD(s.into()), 508 | (0b0101101, 0b00000, _) => RvInsn::FsqrtD(s.into()), 509 | (0b0010001, _, 0b000) => RvInsn::FsgnjD(s.into()), 510 | (0b0010001, _, 0b001) => RvInsn::FsgnjnD(s.into()), 511 | (0b0010001, _, 0b010) => RvInsn::FsgnjxD(s.into()), 512 | (0b0010101, _, 0b000) => RvInsn::FminD(s.into()), 513 | (0b0010101, _, 0b001) => RvInsn::FmaxD(s.into()), 514 | (0b0100000, 0b00001, _) => RvInsn::FcvtSD(s.into()), 515 | (0b0100001, 0b00000, _) => RvInsn::FcvtDS(s.into()), 516 | (0b1010001, _, 0b010) => RvInsn::FeqD(s.into()), 517 | (0b1010001, _, 0b001) => RvInsn::FltD(s.into()), 518 | (0b1010001, _, 0b000) => RvInsn::FleD(s.into()), 519 | (0b1110001, 0b00000, 0b001) => RvInsn::FclassD(s.into()), 520 | (0b1100001, 0b00000, _) => RvInsn::FcvtWD(s.into()), 521 | (0b1100001, 0b00001, _) => RvInsn::FcvtWuD(s.into()), 522 | (0b1101001, 0b00000, _) => RvInsn::FcvtDW(s.into()), 523 | (0b1101001, 0b00001, _) => RvInsn::FcvtDWu(s.into()), 524 | 525 | // RV64D 526 | (0b1100001, 0b00010, _) => RvInsn::FcvtLD(s.into()), 527 | (0b1100001, 0b00011, _) => RvInsn::FcvtLuD(s.into()), 528 | (0b1110001, 0b00000, 0b000) => RvInsn::FmvXD(s.into()), 529 | (0b1101001, 0b00010, _) => RvInsn::FcvtDL(s.into()), 530 | (0b1101001, 0b00011, _) => RvInsn::FcvtDLu(s.into()), 531 | (0b1111001, 0b00000, 0b000) => RvInsn::FmvDX(s.into()), 532 | 533 | _ => RvInsn::Invalid(insn), 534 | } 535 | } 536 | 537 | fn disas_branch(insn: u32) -> RvInsn { 538 | let s = disas_b(insn); 539 | match s.sb_funct3() { 540 | 0b000 => RvInsn::Beq(s.into()), 541 | 0b001 => RvInsn::Bne(s.into()), 542 | 0b100 => RvInsn::Blt(s.into()), 543 | 0b101 => RvInsn::Bge(s.into()), 544 | 0b110 => RvInsn::Bltu(s.into()), 545 | 0b111 => RvInsn::Bgeu(s.into()), 546 | _ => RvInsn::Invalid(insn), 547 | } 548 | } 549 | 550 | fn disas_jalr(insn: u32) -> RvInsn { 551 | let s = disas_i(insn); 552 | match s.i_funct3() { 553 | 0b000 => RvInsn::Jalr(s.into()), 554 | _ => RvInsn::Invalid(insn), 555 | } 556 | } 557 | 558 | fn disas_system(insn: u32) -> RvInsn { 559 | match insn { 560 | 0x00000073 => RvInsn::Ecall, 561 | 0x00100073 => RvInsn::Ebreak, 562 | _ => RvInsn::Invalid(insn), 563 | } 564 | } 565 | -------------------------------------------------------------------------------- /src/rv/rvc.rs: -------------------------------------------------------------------------------- 1 | use super::disas_helper::simm_from_uimm; 2 | use super::{ITypeArgs, RTypeArgs, RvInsn, SBTypeArgs, ShiftArgs, UJTypeArgs}; 3 | 4 | #[derive(PartialEq, Debug)] 5 | pub(super) enum RvCInsn { 6 | Invalid(u16), 7 | Addi4spn { rd: u8, imm: i32 }, 8 | Fld { rd: u8, rs1: u8, imm: i32 }, 9 | Lw { rd: u8, rs1: u8, imm: i32 }, 10 | Flw { rd: u8, rs1: u8, imm: i32 }, 11 | Ld { rd: u8, rs1: u8, imm: i32 }, 12 | Fsd { rs1: u8, rs2: u8, imm: i32 }, 13 | Sw { rs1: u8, rs2: u8, imm: i32 }, 14 | Fsw { rs1: u8, rs2: u8, imm: i32 }, 15 | Sd { rs1: u8, rs2: u8, imm: i32 }, 16 | Addi { rd: u8, imm: i32 }, 17 | Jal { imm: i32 }, 18 | Addiw { rd: u8, imm: i32 }, 19 | Li { rd: u8, imm: i32 }, 20 | Lui { rd: u8, imm: i32 }, 21 | Addi16sp { imm: i32 }, 22 | Srli { rd: u8, imm: u8 }, 23 | Srai { rd: u8, imm: u8 }, 24 | Andi { rd: u8, imm: i32 }, 25 | Sub { rd: u8, rs2: u8 }, 26 | Xor { rd: u8, rs2: u8 }, 27 | Or { rd: u8, rs2: u8 }, 28 | And { rd: u8, rs2: u8 }, 29 | Subw { rd: u8, rs2: u8 }, 30 | Addw { rd: u8, rs2: u8 }, 31 | J { imm: i32 }, 32 | Beqz { rs1: u8, imm: i32 }, 33 | Bnez { rs1: u8, imm: i32 }, 34 | Slli { rd: u8, imm: u8 }, 35 | Fldsp { rd: u8, imm: i32 }, 36 | Lwsp { rd: u8, imm: i32 }, 37 | Flwsp { rd: u8, imm: i32 }, 38 | Ldsp { rd: u8, imm: i32 }, 39 | Jr { rs1: u8 }, 40 | Ebreak, 41 | Jalr { rs1: u8 }, 42 | Mv { rd: u8, rs2: u8 }, 43 | Add { rd: u8, rs2: u8 }, 44 | Fsdsp { rs2: u8, imm: i32 }, 45 | Swsp { rs2: u8, imm: i32 }, 46 | Fswsp { rs2: u8, imm: i32 }, 47 | Sdsp { rs2: u8, imm: i32 }, 48 | } 49 | 50 | impl From for RvInsn { 51 | fn from(insn: RvCInsn) -> Self { 52 | match insn { 53 | RvCInsn::Invalid(x) => Self::Invalid(x as u32), 54 | RvCInsn::Addi4spn { rd, imm } => Self::Addi(ITypeArgs { rd, rs1: 2, imm }), 55 | RvCInsn::Fld { rd, rs1, imm } => Self::Fld(ITypeArgs { rd, rs1, imm }), 56 | RvCInsn::Lw { rd, rs1, imm } => Self::Lw(ITypeArgs { rd, rs1, imm }), 57 | RvCInsn::Flw { rd, rs1, imm } => Self::Flw(ITypeArgs { rd, rs1, imm }), 58 | RvCInsn::Ld { rd, rs1, imm } => Self::Ld(ITypeArgs { rd, rs1, imm }), 59 | RvCInsn::Fsd { rs1, rs2, imm } => Self::Fsd(SBTypeArgs { rs1, rs2, imm }), 60 | RvCInsn::Sw { rs1, rs2, imm } => Self::Sw(SBTypeArgs { rs1, rs2, imm }), 61 | RvCInsn::Fsw { rs1, rs2, imm } => Self::Fsw(SBTypeArgs { rs1, rs2, imm }), 62 | RvCInsn::Sd { rs1, rs2, imm } => Self::Sd(SBTypeArgs { rs1, rs2, imm }), 63 | RvCInsn::Addi { rd, imm } => Self::Addi(ITypeArgs { rd, rs1: rd, imm }), 64 | RvCInsn::Jal { imm } => Self::Jal(UJTypeArgs { rd: 1, imm }), 65 | RvCInsn::Addiw { rd, imm } => Self::Addiw(ITypeArgs { rd, rs1: rd, imm }), 66 | RvCInsn::Li { rd, imm } => Self::Addi(ITypeArgs { rd, rs1: 0, imm }), 67 | RvCInsn::Lui { rd, imm } => Self::Lui(UJTypeArgs { rd, imm }), 68 | RvCInsn::Addi16sp { imm } => Self::Addi(ITypeArgs { rd: 2, rs1: 2, imm }), 69 | RvCInsn::Srli { rd, imm } => Self::Srli(ShiftArgs { 70 | rd, 71 | rs1: rd, 72 | shamt: imm, 73 | }), 74 | RvCInsn::Srai { rd, imm } => Self::Srai(ShiftArgs { 75 | rd, 76 | rs1: rd, 77 | shamt: imm, 78 | }), 79 | RvCInsn::Andi { rd, imm } => Self::Andi(ITypeArgs { rd, rs1: rd, imm }), 80 | RvCInsn::Sub { rd, rs2 } => Self::Sub(RTypeArgs { rd, rs1: rd, rs2 }), 81 | RvCInsn::Xor { rd, rs2 } => Self::Xor(RTypeArgs { rd, rs1: rd, rs2 }), 82 | RvCInsn::Or { rd, rs2 } => Self::Or(RTypeArgs { rd, rs1: rd, rs2 }), 83 | RvCInsn::And { rd, rs2 } => Self::And(RTypeArgs { rd, rs1: rd, rs2 }), 84 | RvCInsn::Subw { rd, rs2 } => Self::Subw(RTypeArgs { rd, rs1: rd, rs2 }), 85 | RvCInsn::Addw { rd, rs2 } => Self::Addw(RTypeArgs { rd, rs1: rd, rs2 }), 86 | RvCInsn::J { imm } => Self::Jal(UJTypeArgs { rd: 0, imm }), 87 | RvCInsn::Beqz { rs1, imm } => Self::Beq(SBTypeArgs { rs1, rs2: 0, imm }), 88 | RvCInsn::Bnez { rs1, imm } => Self::Bne(SBTypeArgs { rs1, rs2: 0, imm }), 89 | RvCInsn::Slli { rd, imm } => Self::Slli(ShiftArgs { 90 | rd, 91 | rs1: rd, 92 | shamt: imm, 93 | }), 94 | RvCInsn::Fldsp { rd, imm } => Self::Fld(ITypeArgs { rd, rs1: 2, imm }), 95 | RvCInsn::Lwsp { rd, imm } => Self::Lw(ITypeArgs { rd, rs1: 2, imm }), 96 | RvCInsn::Flwsp { rd, imm } => Self::Flw(ITypeArgs { rd, rs1: 2, imm }), 97 | RvCInsn::Ldsp { rd, imm } => Self::Ld(ITypeArgs { rd, rs1: 2, imm }), 98 | RvCInsn::Jr { rs1 } => Self::Jalr(ITypeArgs { rd: 0, rs1, imm: 0 }), 99 | RvCInsn::Ebreak => Self::Ebreak, 100 | RvCInsn::Jalr { rs1 } => Self::Jalr(ITypeArgs { rd: 1, rs1, imm: 0 }), 101 | RvCInsn::Mv { rd, rs2 } => Self::Add(RTypeArgs { rd, rs1: 0, rs2 }), 102 | RvCInsn::Add { rd, rs2 } => Self::Add(RTypeArgs { rd, rs1: rd, rs2 }), 103 | RvCInsn::Fsdsp { rs2, imm } => Self::Fsd(SBTypeArgs { rs1: 2, rs2, imm }), 104 | RvCInsn::Swsp { rs2, imm } => Self::Sw(SBTypeArgs { rs1: 2, rs2, imm }), 105 | RvCInsn::Fswsp { rs2, imm } => Self::Fsw(SBTypeArgs { rs1: 2, rs2, imm }), 106 | RvCInsn::Sdsp { rs2, imm } => Self::Sd(SBTypeArgs { rs1: 2, rs2, imm }), 107 | } 108 | } 109 | } 110 | 111 | // Compressed register slot. 112 | struct CReg(u8); 113 | 114 | impl From for u8 { 115 | fn from(x: CReg) -> Self { 116 | x.0 + 8 117 | } 118 | } 119 | 120 | pub(super) struct RvCDecoder { 121 | xlen: usize, 122 | } 123 | 124 | impl RvCDecoder { 125 | pub(super) fn new(xlen: usize) -> Self { 126 | Self { xlen } 127 | } 128 | 129 | pub(super) fn disas(&self, insn: u16) -> RvCInsn { 130 | match insn & 0b11 { 131 | 0b00 => self.disas_00(insn), 132 | 0b01 => self.disas_01(insn), 133 | 0b10 => self.disas_10(insn), 134 | _ => panic!("should never happen"), 135 | } 136 | } 137 | 138 | fn disas_00(&self, insn: u16) -> RvCInsn { 139 | let rs1: u8 = CReg(((insn >> 7) & 0b111) as u8).into(); 140 | let rd: u8 = CReg(((insn >> 2) & 0b111) as u8).into(); 141 | 142 | let imm_slot = (insn >> 5) & 0b11111111; 143 | 144 | let nzuimm54_96_2_3 = { 145 | let a = (imm_slot >> 6) & 0b11; // nzuimm[5:4] 146 | let b = (imm_slot >> 2) & 0b1111; // nzuimm[9:6] 147 | let c = (imm_slot >> 1) & 0b1; // nzuimm[2] 148 | let d = imm_slot & 0b1; // nzuimm[3] 149 | (a << 4) | (b << 6) | (c << 2) | (d << 3) 150 | }; 151 | 152 | let uimm53_76 = { 153 | let a = (imm_slot >> 5) & 0b111; // uimm[5:3] 154 | let b = imm_slot & 0b11; // uimm[7:6] 155 | (a << 3) | (b << 6) 156 | }; 157 | 158 | let uimm53_2_6 = { 159 | let a = (imm_slot >> 5) & 0b111; // uimm[5:3] 160 | let b = (imm_slot >> 1) & 0b1; // uimm[2] 161 | let c = imm_slot & 0b1; // uimm[6] 162 | (a << 3) | (b << 2) | (c << 6) 163 | }; 164 | 165 | match (self.xlen, insn >> 13) { 166 | (_, 0b000) => { 167 | if nzuimm54_96_2_3 != 0 { 168 | RvCInsn::Addi4spn { 169 | rd, 170 | imm: nzuimm54_96_2_3 as i32, 171 | } 172 | } else { 173 | RvCInsn::Invalid(insn) 174 | } 175 | } 176 | (32 | 64, 0b001) => RvCInsn::Fld { 177 | rd, 178 | rs1, 179 | imm: uimm53_76 as i32, 180 | }, 181 | (128, 0b001) => unimplemented!(), 182 | (_, 0b010) => RvCInsn::Lw { 183 | rd, 184 | rs1, 185 | imm: uimm53_2_6 as i32, 186 | }, 187 | (32, 0b011) => RvCInsn::Flw { 188 | rd, 189 | rs1, 190 | imm: uimm53_2_6 as i32, 191 | }, 192 | (64 | 128, 0b011) => RvCInsn::Ld { 193 | rd, 194 | rs1, 195 | imm: uimm53_76 as i32, 196 | }, 197 | (32 | 64, 0b101) => RvCInsn::Fsd { 198 | rs1, 199 | rs2: rd, 200 | imm: uimm53_76 as i32, 201 | }, 202 | (128, 0b101) => unimplemented!(), 203 | (_, 0b110) => RvCInsn::Sw { 204 | rs1, 205 | rs2: rd, 206 | imm: uimm53_2_6 as i32, 207 | }, 208 | (32, 0b111) => RvCInsn::Fsw { 209 | rs1, 210 | rs2: rd, 211 | imm: uimm53_2_6 as i32, 212 | }, 213 | (64 | 128, 0b111) => RvCInsn::Sd { 214 | rs1, 215 | rs2: rd, 216 | imm: uimm53_76 as i32, 217 | }, 218 | 219 | _ => RvCInsn::Invalid(insn), 220 | } 221 | } 222 | 223 | fn disas_01(&self, insn: u16) -> RvCInsn { 224 | let b15_13 = insn >> 13; // insn[15:13] 225 | let b12 = (insn >> 12) & 0b1; // insn[12] 226 | let b11_7 = (insn >> 7) & 0b11111; // insn[11:7] -- full rd slot 227 | let b6_2 = (insn >> 2) & 0b11111; // insn[6:2] 228 | 229 | let full_rd = b11_7 as u8; 230 | let rd: u8 = CReg(((insn >> 7) & 0b111) as u8).into(); // insn[9:7] - rs1'/rd' 231 | 232 | let imm5_40 = simm_from_uimm((b12 << 5 | b6_2) as u32, 6); 233 | let imm17_1612 = imm5_40 << 12; 234 | 235 | let imm9_4_6_87_5 = { 236 | let a = b12; 237 | let b = (insn >> 6) & 0b1; 238 | let c = (insn >> 5) & 0b1; 239 | let d = (insn >> 3) & 0b11; 240 | let e = (insn >> 2) & 0b1; 241 | simm_from_uimm((a << 9 | b << 4 | c << 6 | d << 7 | e << 5) as u32, 10) 242 | }; 243 | 244 | let imm_11_4_98_10_6_7_31_5 = { 245 | let a = b12; 246 | let b = (insn >> 11) & 0b1; 247 | let c = (insn >> 9) & 0b11; 248 | let d = (insn >> 8) & 0b1; 249 | let e = (insn >> 7) & 0b1; 250 | let f = (insn >> 6) & 0b1; 251 | let g = (insn >> 3) & 0b111; 252 | let h = (insn >> 2) & 0b1; 253 | simm_from_uimm( 254 | (a << 11 | b << 4 | c << 8 | d << 10 | e << 6 | f << 7 | g << 1 | h << 5) as u32, 255 | 12, 256 | ) 257 | }; 258 | 259 | let imm_8_43_76_21_5 = { 260 | let a = b12; 261 | let b = (insn >> 10) & 0b11; 262 | let c = (insn >> 5) & 0b11; 263 | let d = (insn >> 3) & 0b11; 264 | let e = (insn >> 2) & 0b1; 265 | simm_from_uimm((a << 8 | b << 3 | c << 6 | d << 1 | e << 5) as u32, 9) 266 | }; 267 | 268 | match (self.xlen, b15_13) { 269 | // c.nop and HINT of c.addi are not handled 270 | (_, 0b000) => RvCInsn::Addi { 271 | rd: full_rd, 272 | imm: imm5_40, 273 | }, 274 | (32, 0b001) => RvCInsn::Jal { 275 | imm: imm_11_4_98_10_6_7_31_5, 276 | }, 277 | (64 | 128, 0b001) => RvCInsn::Addiw { 278 | rd: full_rd, 279 | imm: imm5_40, 280 | }, 281 | (_, 0b010) => RvCInsn::Li { 282 | rd: full_rd, 283 | imm: imm5_40, 284 | }, 285 | (_, 0b011) => match full_rd { 286 | 2 => RvCInsn::Addi16sp { imm: imm9_4_6_87_5 }, 287 | // HINT (rd=0) not handled 288 | _ => RvCInsn::Lui { 289 | rd, 290 | imm: imm17_1612, 291 | }, 292 | }, 293 | (_, 0b100) => self.disas_01_100(insn), 294 | (_, 0b101) => RvCInsn::J { 295 | imm: imm_11_4_98_10_6_7_31_5, 296 | }, 297 | (_, 0b110) => RvCInsn::Beqz { 298 | rs1: rd, 299 | imm: imm_8_43_76_21_5, 300 | }, 301 | (_, 0b111) => RvCInsn::Bnez { 302 | rs1: rd, 303 | imm: imm_8_43_76_21_5, 304 | }, 305 | _ => RvCInsn::Invalid(insn), 306 | } 307 | } 308 | 309 | fn disas_01_100(&self, insn: u16) -> RvCInsn { 310 | let b12 = (insn >> 12) & 0b1; // insn[12] 311 | let b11_10 = (insn >> 10) & 0b11; // insn[11:10] 312 | let b6_5 = (insn >> 5) & 0b11; // insn[6:5] 313 | let b6_2 = (insn >> 2) & 0b11111; // insn[6:2] 314 | 315 | let rd: u8 = CReg(((insn >> 7) & 0b111) as u8).into(); // insn[9:7] - rs1'/rd' 316 | let rs2: u8 = CReg(((insn >> 2) & 0b111) as u8).into(); // insn[4:2] - rs2' 317 | 318 | let uimm5_40 = (b12 << 5 | b6_2) as u8; 319 | let imm5_40 = simm_from_uimm(uimm5_40 as u32, 6); 320 | 321 | match (self.xlen, b12, b11_10, b6_5) { 322 | (32, 1, 0b00, _) => RvCInsn::Invalid(insn), // RV32 NSE 323 | (_, _, 0b00, _) => RvCInsn::Srli { rd, imm: uimm5_40 }, 324 | (32, 1, 0b01, _) => RvCInsn::Invalid(insn), // RV32 NSE 325 | (_, _, 0b01, _) => RvCInsn::Srai { rd, imm: uimm5_40 }, 326 | (_, _, 0b10, _) => RvCInsn::Andi { rd, imm: imm5_40 }, 327 | (_, 0, 0b11, 0b00) => RvCInsn::Sub { rd, rs2 }, 328 | (_, 0, 0b11, 0b01) => RvCInsn::Xor { rd, rs2 }, 329 | (_, 0, 0b11, 0b10) => RvCInsn::Or { rd, rs2 }, 330 | (_, 0, 0b11, 0b11) => RvCInsn::And { rd, rs2 }, 331 | (64 | 128, 1, 0b11, 0b00) => RvCInsn::Subw { rd, rs2 }, 332 | (64 | 128, 1, 0b11, 0b01) => RvCInsn::Addw { rd, rs2 }, 333 | _ => RvCInsn::Invalid(insn), 334 | } 335 | } 336 | 337 | fn disas_10(&self, insn: u16) -> RvCInsn { 338 | let b15_13 = insn >> 13; // insn[15:13] 339 | let b12 = (insn >> 12) & 0b1; // insn[12] 340 | 341 | // these are full slots, unlike the other quadrants 342 | let rd = ((insn >> 7) & 0b11111) as u8; 343 | let rs2 = ((insn >> 2) & 0b11111) as u8; 344 | 345 | let uimm5_40 = (b12 as u8) << 5 | rs2; 346 | let uimm5_43_86 = { 347 | let a = b12; 348 | let b = (insn >> 5) & 0b11; 349 | let c = (insn >> 2) & 0b111; 350 | a << 5 | b << 3 | c << 6 351 | }; 352 | let uimm5_42_76 = { 353 | let a = b12; 354 | let b = (insn >> 4) & 0b111; 355 | let c = (insn >> 2) & 0b11; 356 | a << 5 | b << 2 | c << 6 357 | }; 358 | 359 | let uimm53_86 = { 360 | let a = (insn >> 10) & 0b111; 361 | let b = (insn >> 7) & 0b111; 362 | a << 3 | b << 6 363 | }; 364 | let uimm52_76 = { 365 | let a = (insn >> 9) & 0b1111; 366 | let b = (insn >> 7) & 0b11; 367 | a << 2 | b << 6 368 | }; 369 | 370 | match (self.xlen, b15_13, b12, rd, rs2) { 371 | (32, 0b000, 1, _, _) => RvCInsn::Invalid(insn), // RV32 NSE 372 | (_, 0b000, _, _, _) => RvCInsn::Slli { rd, imm: uimm5_40 }, 373 | (32 | 64, 0b001, _, _, _) => RvCInsn::Fldsp { 374 | rd, 375 | imm: uimm5_43_86 as i32, 376 | }, 377 | (_, 0b010, _, 0, _) => RvCInsn::Invalid(insn), 378 | (_, 0b010, _, _, _) => RvCInsn::Lwsp { 379 | rd, 380 | imm: uimm5_42_76 as i32, 381 | }, 382 | (32, 0b011, _, _, _) => RvCInsn::Flwsp { 383 | rd, 384 | imm: uimm5_42_76 as i32, 385 | }, 386 | (64 | 128, 0b011, _, 0, _) => RvCInsn::Invalid(insn), 387 | (64 | 128, 0b011, _, _, _) => RvCInsn::Ldsp { 388 | rd, 389 | imm: uimm5_43_86 as i32, 390 | }, 391 | (_, 0b100, 0, 0, 0) => RvCInsn::Invalid(insn), 392 | (_, 0b100, 0, _, 0) => RvCInsn::Jr { rs1: rd }, 393 | (_, 0b100, 0, _, _) => RvCInsn::Mv { rd, rs2 }, // HINT (rd=0) not handled 394 | (_, 0b100, 1, 0, 0) => RvCInsn::Ebreak, 395 | (_, 0b100, 1, _, 0) => RvCInsn::Jalr { rs1: rd }, 396 | (_, 0b100, 1, _, _) => RvCInsn::Add { rd, rs2 }, // HINT (rd=0) not handled 397 | (32 | 64, 0b101, _, _, _) => RvCInsn::Fsdsp { 398 | rs2, 399 | imm: uimm53_86 as i32, 400 | }, 401 | (128, 0b101, _, _, _) => unimplemented!(), 402 | (32 | 64, 0b110, _, _, _) => RvCInsn::Swsp { 403 | rs2, 404 | imm: uimm52_76 as i32, 405 | }, 406 | (32, 0b111, _, _, _) => RvCInsn::Fswsp { 407 | rs2, 408 | imm: uimm52_76 as i32, 409 | }, 410 | (64 | 128, 0b111, _, _, _) => RvCInsn::Sdsp { 411 | rs2, 412 | imm: uimm53_86 as i32, 413 | }, 414 | 415 | _ => RvCInsn::Invalid(insn), 416 | } 417 | } 418 | } 419 | 420 | #[cfg(test)] 421 | mod tests { 422 | use super::*; 423 | 424 | #[test] 425 | fn test_rv64c_quadrant_00() { 426 | let d = RvCDecoder::new(64); 427 | 428 | // unimp 429 | assert_eq!(d.disas(0x0000), RvCInsn::Invalid(0)); 430 | 431 | // c.fld fs0,112(a0) 432 | assert_eq!( 433 | d.disas(0x3920), 434 | RvCInsn::Fld { 435 | rd: 8, 436 | rs1: 10, 437 | imm: 112 438 | } 439 | ); 440 | 441 | // c.ld a5,0(s0) 442 | assert_eq!( 443 | d.disas(0x601c), 444 | RvCInsn::Ld { 445 | rd: 15, 446 | rs1: 8, 447 | imm: 0 448 | } 449 | ); 450 | 451 | // c.addi4spn s1,sp,168 452 | assert_eq!(d.disas(0x1124), RvCInsn::Addi4spn { rd: 9, imm: 168 }); 453 | 454 | // c.sd a0,8(a5) 455 | assert_eq!( 456 | d.disas(0xe788), 457 | RvCInsn::Sd { 458 | rs1: 15, 459 | rs2: 10, 460 | imm: 8 461 | } 462 | ) 463 | } 464 | 465 | #[test] 466 | fn test_rv64c_quadrant_01() { 467 | let d = RvCDecoder::new(64); 468 | 469 | // c.addi sp,-32 470 | assert_eq!(d.disas(0x1101), RvCInsn::Addi { rd: 2, imm: -32 }); 471 | 472 | // c.lui a5,0x10 473 | assert_eq!( 474 | d.disas(0x67c1), 475 | RvCInsn::Lui { 476 | rd: 15, 477 | imm: 0x10 << 12 478 | } 479 | ); 480 | 481 | // c.li a5,0 482 | assert_eq!(d.disas(0x4781), RvCInsn::Li { rd: 15, imm: 0 }); 483 | 484 | // c.li s4,-1 485 | assert_eq!(d.disas(0x5a7d), RvCInsn::Li { rd: 20, imm: -1 }); 486 | 487 | // c.li a0,12 488 | assert_eq!(d.disas(0x4531), RvCInsn::Li { rd: 10, imm: 12 }); 489 | 490 | // c.sub a2,s0 491 | assert_eq!(d.disas(0x8e01), RvCInsn::Sub { rd: 12, rs2: 8 }); 492 | 493 | // c.xor a4,a3 494 | assert_eq!(d.disas(0x8f35), RvCInsn::Xor { rd: 14, rs2: 13 }); 495 | 496 | // c.beqz a0, +38 497 | assert_eq!(d.disas(0xc11d), RvCInsn::Beqz { rs1: 10, imm: 38 }) 498 | } 499 | 500 | #[test] 501 | fn test_rv64c_quadrant_10() { 502 | let d = RvCDecoder::new(64); 503 | 504 | // c.slli a3,0x4 505 | assert_eq!(d.disas(0x0692), RvCInsn::Slli { rd: 13, imm: 4 }); 506 | 507 | // c.fldsp fa7,136(sp) 508 | assert_eq!(d.disas(0x28aa), RvCInsn::Fldsp { rd: 17, imm: 136 }); 509 | 510 | // c.lwsp a3,132(sp) 511 | assert_eq!(d.disas(0x469a), RvCInsn::Lwsp { rd: 13, imm: 132 }); 512 | 513 | // c.add a5,a4 514 | assert_eq!(d.disas(0x97ba), RvCInsn::Add { rd: 15, rs2: 14 }); 515 | 516 | // c.mv a4,s11 517 | assert_eq!(d.disas(0x876e), RvCInsn::Mv { rd: 14, rs2: 27 }); 518 | 519 | // c.jr a5 520 | assert_eq!(d.disas(0x8782), RvCInsn::Jr { rs1: 15 }); 521 | 522 | // c.jr ra 523 | assert_eq!(d.disas(0x8082), RvCInsn::Jr { rs1: 1 }); 524 | 525 | // c.ebreak 526 | assert_eq!(d.disas(0x9002), RvCInsn::Ebreak); 527 | 528 | // c.jalr a5 529 | assert_eq!(d.disas(0x9782), RvCInsn::Jalr { rs1: 15 }); 530 | } 531 | } 532 | -------------------------------------------------------------------------------- /src/exec/interp/mod.rs: -------------------------------------------------------------------------------- 1 | use super::mem::{GuestAddr, GuestMmu}; 2 | use super::{RvIsaState, StopReason}; 3 | use crate::rv::{RvDecoder, RvInsn}; 4 | 5 | mod syscall; 6 | 7 | pub struct RvInterpreterExecutor<'a> { 8 | debug: bool, 9 | shamt_mask: u64, 10 | 11 | state: &'a mut RvIsaState, 12 | mmu: &'a mut GuestMmu, 13 | 14 | decoder: RvDecoder, 15 | } 16 | 17 | fn sext_u8(x: u8) -> u64 { 18 | x as i8 as i64 as u64 19 | } 20 | 21 | fn sext_u16(x: u16) -> u64 { 22 | x as i16 as i64 as u64 23 | } 24 | 25 | fn sext_u32(x: u32) -> u64 { 26 | x as i32 as i64 as u64 27 | } 28 | 29 | impl<'a> RvInterpreterExecutor<'a> { 30 | pub fn new(xlen: usize, state: &'a mut RvIsaState, mmu: &'a mut GuestMmu) -> Self { 31 | Self { 32 | debug: false, 33 | shamt_mask: (xlen - 1) as u64, 34 | state, 35 | mmu, 36 | decoder: RvDecoder::new(xlen), 37 | } 38 | } 39 | 40 | pub fn debug(&mut self, val: bool) { 41 | self.debug = val; 42 | } 43 | 44 | pub fn stack(&mut self, len: usize) -> ::std::io::Result<()> { 45 | let stack_block = self.mmu.mmap(len, true)?; 46 | let stack_top = stack_block + len; 47 | self.state.set_x(2, stack_top.as_u64()); 48 | Ok(()) 49 | } 50 | 51 | fn get_u8(&self, gaddr: GuestAddr) -> Result { 52 | if let Some(haddr) = self.mmu.g2h(gaddr) { 53 | Ok(unsafe { (haddr.as_u64() as *const u8).read() }) 54 | } else { 55 | Err(StopReason::Segv { 56 | read: true, 57 | gaddr: gaddr.into(), 58 | }) 59 | } 60 | } 61 | 62 | fn get_u16(&self, gaddr: GuestAddr) -> Result { 63 | if let Some(haddr) = self.mmu.g2h(gaddr) { 64 | Ok(unsafe { (haddr.as_u64() as *const u16).read() }) 65 | } else { 66 | Err(StopReason::Segv { 67 | read: true, 68 | gaddr: gaddr.into(), 69 | }) 70 | } 71 | } 72 | 73 | fn get_u32(&self, gaddr: GuestAddr) -> Result { 74 | if let Some(haddr) = self.mmu.g2h(gaddr) { 75 | Ok(unsafe { (haddr.as_u64() as *const u32).read() }) 76 | } else { 77 | Err(StopReason::Segv { 78 | read: true, 79 | gaddr: gaddr.into(), 80 | }) 81 | } 82 | } 83 | 84 | fn get_u64(&self, gaddr: GuestAddr) -> Result { 85 | if let Some(haddr) = self.mmu.g2h(gaddr) { 86 | Ok(unsafe { (haddr.as_u64() as *const u64).read() }) 87 | } else { 88 | Err(StopReason::Segv { 89 | read: true, 90 | gaddr: gaddr.into(), 91 | }) 92 | } 93 | } 94 | 95 | fn set_u8(&self, gaddr: GuestAddr, val: u8) -> Result<(), StopReason> { 96 | if let Some(haddr) = self.mmu.g2h(gaddr) { 97 | Ok(unsafe { (haddr.as_u64() as *mut u8).write(val) }) 98 | } else { 99 | Err(StopReason::Segv { 100 | read: false, 101 | gaddr: gaddr.into(), 102 | }) 103 | } 104 | } 105 | 106 | fn set_u16(&self, gaddr: GuestAddr, val: u16) -> Result<(), StopReason> { 107 | if let Some(haddr) = self.mmu.g2h(gaddr) { 108 | Ok(unsafe { (haddr.as_u64() as *mut u16).write(val) }) 109 | } else { 110 | Err(StopReason::Segv { 111 | read: false, 112 | gaddr: gaddr.into(), 113 | }) 114 | } 115 | } 116 | 117 | fn set_u32(&self, gaddr: GuestAddr, val: u32) -> Result<(), StopReason> { 118 | if let Some(haddr) = self.mmu.g2h(gaddr) { 119 | Ok(unsafe { (haddr.as_u64() as *mut u32).write(val) }) 120 | } else { 121 | Err(StopReason::Segv { 122 | read: false, 123 | gaddr: gaddr.into(), 124 | }) 125 | } 126 | } 127 | 128 | fn set_u64(&self, gaddr: GuestAddr, val: u64) -> Result<(), StopReason> { 129 | if let Some(haddr) = self.mmu.g2h(gaddr) { 130 | Ok(unsafe { (haddr.as_u64() as *mut u64).write(val) }) 131 | } else { 132 | Err(StopReason::Segv { 133 | read: false, 134 | gaddr: gaddr.into(), 135 | }) 136 | } 137 | } 138 | 139 | fn pcrel(&self, imm: i64) -> u64 { 140 | (self.state.get_pc() as i64 + imm) as u64 141 | } 142 | 143 | fn gx(&self, idx: u8) -> u64 { 144 | self.state.get_x(idx) 145 | } 146 | 147 | fn sx(&mut self, idx: u8, val: u64) { 148 | self.state.set_x(idx, val) 149 | } 150 | 151 | fn gf32(&self, idx: u8) -> f32 { 152 | self.state.get_f32(idx) 153 | } 154 | 155 | fn sf32(&mut self, idx: u8, val: f32) { 156 | self.state.set_f32(idx, val) 157 | } 158 | 159 | fn gf64(&self, idx: u8) -> f64 { 160 | self.state.get_f64(idx) 161 | } 162 | 163 | fn sf64(&mut self, idx: u8, val: f64) { 164 | self.state.set_f64(idx, val) 165 | } 166 | 167 | // returns None if successful exit 168 | pub fn exec(&mut self, entry_pc: u64) -> Option { 169 | self.state.set_pc(entry_pc); 170 | 171 | loop { 172 | let x = self.exec_one(); 173 | match x { 174 | StopReason::Next | StopReason::ContinueAt(_) => {} 175 | _ => return Some(x), 176 | } 177 | } 178 | } 179 | 180 | fn fetch_insn(&self) -> Result<(RvInsn, usize), StopReason> { 181 | let pc = self.state.get_pc(); 182 | if self.debug { 183 | println!("pc = {:016x}", pc); 184 | } 185 | 186 | // XXX: this is duplicating code from decoder, ideally decoder will 187 | // handle all of this 188 | let lsb_byte = self.get_u8(pc.into())?; 189 | if lsb_byte & 0b11 == 0b11 { 190 | // 32-bit 191 | let insn_word = self.get_u32(pc.into())?; 192 | Ok((self.decoder.disas_32bit(insn_word), 4)) 193 | } else { 194 | // 16-bit 195 | let insn_word = self.get_u16(pc.into())?; 196 | Ok((self.decoder.disas_16bit(insn_word), 2)) 197 | } 198 | } 199 | 200 | fn exec_one(&mut self) -> StopReason { 201 | let (insn, len) = match self.fetch_insn() { 202 | Ok((insn, len)) => (insn, len), 203 | Err(e) => return e, 204 | }; 205 | if self.debug { 206 | println!("decoded {}b: {:?}", len, insn); 207 | } 208 | 209 | let res = self.interpret_one(&insn, len); 210 | 211 | let new_pc = if let StopReason::ContinueAt(x) = res { 212 | x 213 | } else { 214 | self.state.get_pc() + (len as u64) 215 | }; 216 | self.state.set_pc(new_pc); 217 | 218 | res 219 | } 220 | 221 | // returns next pc 222 | fn interpret_one(&mut self, insn: &RvInsn, insn_len: usize) -> StopReason { 223 | match insn { 224 | RvInsn::Invalid(_) => StopReason::ReservedInsn, 225 | RvInsn::Ecall => self.do_syscall(), 226 | RvInsn::Ebreak => StopReason::Break, 227 | RvInsn::Lui(a) => { 228 | self.sx(a.rd, a.imm as u64); 229 | StopReason::Next 230 | } 231 | RvInsn::Auipc(a) => { 232 | self.sx(a.rd, self.pcrel(a.imm as i64)); 233 | StopReason::Next 234 | } 235 | RvInsn::Jal(a) => { 236 | let pc = self.state.get_pc(); 237 | self.sx(a.rd, pc + insn_len as u64); 238 | StopReason::ContinueAt((pc as i64 + a.imm as i64) as u64) 239 | } 240 | RvInsn::Jalr(a) => { 241 | let pc = self.state.get_pc(); 242 | self.sx(a.rd, pc + insn_len as u64); 243 | StopReason::ContinueAt((self.gx(a.rs1) as i64 + a.imm as i64) as u64) 244 | } 245 | RvInsn::Beq(a) => { 246 | let v1 = self.gx(a.rs1); 247 | let v2 = self.gx(a.rs2); 248 | if v1 == v2 { 249 | StopReason::ContinueAt(self.pcrel(a.imm as i64)) 250 | } else { 251 | StopReason::Next 252 | } 253 | } 254 | RvInsn::Bne(a) => { 255 | // TODO: dedup 256 | let v1 = self.gx(a.rs1); 257 | let v2 = self.gx(a.rs2); 258 | if v1 != v2 { 259 | StopReason::ContinueAt(self.pcrel(a.imm as i64)) 260 | } else { 261 | StopReason::Next 262 | } 263 | } 264 | RvInsn::Blt(a) => { 265 | let v1 = self.gx(a.rs1) as i64; 266 | let v2 = self.gx(a.rs2) as i64; 267 | if v1 < v2 { 268 | StopReason::ContinueAt(self.pcrel(a.imm as i64)) 269 | } else { 270 | StopReason::Next 271 | } 272 | } 273 | RvInsn::Bge(a) => { 274 | // TODO: dedup 275 | let v1 = self.gx(a.rs1) as i64; 276 | let v2 = self.gx(a.rs2) as i64; 277 | if v1 >= v2 { 278 | StopReason::ContinueAt(self.pcrel(a.imm as i64)) 279 | } else { 280 | StopReason::Next 281 | } 282 | } 283 | RvInsn::Bltu(a) => { 284 | let v1 = self.gx(a.rs1); 285 | let v2 = self.gx(a.rs2); 286 | if v1 < v2 { 287 | StopReason::ContinueAt(self.pcrel(a.imm as i64)) 288 | } else { 289 | StopReason::Next 290 | } 291 | } 292 | RvInsn::Bgeu(a) => { 293 | // TODO: dedup 294 | let v1 = self.gx(a.rs1) as i64; 295 | let v2 = self.gx(a.rs2) as i64; 296 | if v1 >= v2 { 297 | StopReason::ContinueAt(self.pcrel(a.imm as i64)) 298 | } else { 299 | StopReason::Next 300 | } 301 | } 302 | RvInsn::Lb(a) => { 303 | let addr = (self.gx(a.rs1) as i64 + a.imm as i64) as u64; 304 | match self.get_u8(addr.into()) { 305 | Ok(v) => { 306 | self.sx(a.rd, sext_u8(v)); 307 | StopReason::Next 308 | } 309 | Err(e) => e, 310 | } 311 | } 312 | RvInsn::Lh(a) => { 313 | let addr = (self.gx(a.rs1) as i64 + a.imm as i64) as u64; 314 | match self.get_u16(addr.into()) { 315 | Ok(v) => { 316 | self.sx(a.rd, sext_u16(v)); 317 | StopReason::Next 318 | } 319 | Err(e) => e, 320 | } 321 | } 322 | RvInsn::Lw(a) => { 323 | let addr = (self.gx(a.rs1) as i64 + a.imm as i64) as u64; 324 | match self.get_u32(addr.into()) { 325 | Ok(v) => { 326 | self.sx(a.rd, sext_u32(v)); 327 | StopReason::Next 328 | } 329 | Err(e) => e, 330 | } 331 | } 332 | RvInsn::Lbu(a) => { 333 | let addr = (self.gx(a.rs1) as i64 + a.imm as i64) as u64; 334 | match self.get_u8(addr.into()) { 335 | Ok(v) => { 336 | self.sx(a.rd, v as u64); 337 | StopReason::Next 338 | } 339 | Err(e) => e, 340 | } 341 | } 342 | RvInsn::Lhu(a) => { 343 | let addr = (self.gx(a.rs1) as i64 + a.imm as i64) as u64; 344 | match self.get_u16(addr.into()) { 345 | Ok(v) => { 346 | self.sx(a.rd, v as u64); 347 | StopReason::Next 348 | } 349 | Err(e) => e, 350 | } 351 | } 352 | RvInsn::Sb(a) => { 353 | let addr = (self.gx(a.rs1) as i64 + a.imm as i64) as u64; 354 | self.set_u8(addr.into(), self.gx(a.rs2) as u8) 355 | .err() 356 | .unwrap_or(StopReason::Next) 357 | } 358 | RvInsn::Sh(a) => { 359 | let addr = (self.gx(a.rs1) as i64 + a.imm as i64) as u64; 360 | self.set_u16(addr.into(), self.gx(a.rs2) as u16) 361 | .err() 362 | .unwrap_or(StopReason::Next) 363 | } 364 | RvInsn::Sw(a) => { 365 | let addr = (self.gx(a.rs1) as i64 + a.imm as i64) as u64; 366 | self.set_u32(addr.into(), self.gx(a.rs2) as u32) 367 | .err() 368 | .unwrap_or(StopReason::Next) 369 | } 370 | RvInsn::Addi(a) => { 371 | let v = self.gx(a.rs1) as i64 + a.imm as i64; 372 | self.sx(a.rd, v as u64); 373 | StopReason::Next 374 | } 375 | RvInsn::Slti(a) => { 376 | let v = if (self.gx(a.rs1) as i64) < a.imm as i64 { 377 | 1 378 | } else { 379 | 0 380 | }; 381 | self.sx(a.rd, v); 382 | StopReason::Next 383 | } 384 | RvInsn::Sltiu(a) => { 385 | let v = if self.gx(a.rs1) < a.imm as i64 as u64 { 386 | 1 387 | } else { 388 | 0 389 | }; 390 | self.sx(a.rd, v); 391 | StopReason::Next 392 | } 393 | RvInsn::Xori(a) => { 394 | let v = self.gx(a.rs1) ^ (a.imm as i64 as u64); 395 | self.sx(a.rd, v); 396 | StopReason::Next 397 | } 398 | RvInsn::Ori(a) => { 399 | let v = self.gx(a.rs1) | (a.imm as i64 as u64); 400 | self.sx(a.rd, v); 401 | StopReason::Next 402 | } 403 | RvInsn::Andi(a) => { 404 | let v = self.gx(a.rs1) & (a.imm as i64 as u64); 405 | self.sx(a.rd, v); 406 | StopReason::Next 407 | } 408 | RvInsn::Slli(a) => { 409 | let v = self.gx(a.rs1) << a.shamt; 410 | self.sx(a.rd, v); 411 | StopReason::Next 412 | } 413 | RvInsn::Srli(a) => { 414 | let v = self.gx(a.rs1) >> a.shamt; 415 | self.sx(a.rd, v); 416 | StopReason::Next 417 | } 418 | RvInsn::Srai(a) => { 419 | let v = self.gx(a.rs1) as i64 >> a.shamt; 420 | self.sx(a.rd, v as u64); 421 | StopReason::Next 422 | } 423 | RvInsn::Add(a) => { 424 | let v = self.gx(a.rs1) as i64 + self.gx(a.rs2) as i64; 425 | self.sx(a.rd, v as u64); 426 | StopReason::Next 427 | } 428 | RvInsn::Sub(a) => { 429 | let v = self.gx(a.rs1) as i64 - self.gx(a.rs2) as i64; 430 | self.sx(a.rd, v as u64); 431 | StopReason::Next 432 | } 433 | RvInsn::Sll(a) => { 434 | let v = self.gx(a.rs1) << (self.gx(a.rs2) & self.shamt_mask); 435 | self.sx(a.rd, v); 436 | StopReason::Next 437 | } 438 | RvInsn::Slt(a) => { 439 | let v = if (self.gx(a.rs1) as i64) < self.gx(a.rs2) as i64 { 440 | 1 441 | } else { 442 | 0 443 | }; 444 | self.sx(a.rd, v); 445 | StopReason::Next 446 | } 447 | RvInsn::Sltu(a) => { 448 | let v = if self.gx(a.rs1) < self.gx(a.rs2) { 449 | 1 450 | } else { 451 | 0 452 | }; 453 | self.sx(a.rd, v); 454 | StopReason::Next 455 | } 456 | RvInsn::Xor(a) => { 457 | let v = self.gx(a.rs1) ^ self.gx(a.rs2); 458 | self.sx(a.rd, v); 459 | StopReason::Next 460 | } 461 | RvInsn::Srl(a) => { 462 | let v = self.gx(a.rs1) >> (self.gx(a.rs2) & self.shamt_mask); 463 | self.sx(a.rd, v); 464 | StopReason::Next 465 | } 466 | RvInsn::Sra(a) => { 467 | let v = self.gx(a.rs1) as i64 >> (self.gx(a.rs2) & self.shamt_mask); 468 | self.sx(a.rd, v as u64); 469 | StopReason::Next 470 | } 471 | RvInsn::Or(a) => { 472 | let v = self.gx(a.rs1) | self.gx(a.rs2); 473 | self.sx(a.rd, v); 474 | StopReason::Next 475 | } 476 | RvInsn::And(a) => { 477 | let v = self.gx(a.rs1) & self.gx(a.rs2); 478 | self.sx(a.rd, v); 479 | StopReason::Next 480 | } 481 | RvInsn::Fence(_) => { 482 | // TODO: currently all treated as full fences 483 | std::sync::atomic::fence(std::sync::atomic::Ordering::SeqCst); 484 | StopReason::Next 485 | } 486 | RvInsn::FenceI(_) => todo!(), 487 | RvInsn::Lwu(a) => { 488 | let addr = (self.gx(a.rs1) as i64 + a.imm as i64) as u64; 489 | match self.get_u32(addr.into()) { 490 | Ok(v) => { 491 | self.sx(a.rd, v as u64); 492 | StopReason::Next 493 | } 494 | Err(e) => e, 495 | } 496 | } 497 | RvInsn::Ld(a) => { 498 | let addr = (self.gx(a.rs1) as i64 + a.imm as i64) as u64; 499 | match self.get_u64(addr.into()) { 500 | Ok(v) => { 501 | self.sx(a.rd, v); 502 | StopReason::Next 503 | } 504 | Err(e) => e, 505 | } 506 | } 507 | RvInsn::Sd(a) => { 508 | let addr = (self.gx(a.rs1) as i64 + a.imm as i64) as u64; 509 | self.set_u64(addr.into(), self.gx(a.rs2)) 510 | .err() 511 | .unwrap_or(StopReason::Next) 512 | } 513 | RvInsn::Addiw(a) => { 514 | let v = self.gx(a.rs1) as i32 + a.imm as i32; 515 | self.sx(a.rd, v as i64 as u64); 516 | StopReason::Next 517 | } 518 | RvInsn::Slliw(a) => { 519 | let v = (self.gx(a.rs1) as u32) << a.shamt; 520 | self.sx(a.rd, v as i32 as i64 as u64); 521 | StopReason::Next 522 | } 523 | RvInsn::Srliw(a) => { 524 | let v = self.gx(a.rs1) as u32 >> a.shamt; 525 | self.sx(a.rd, v as i32 as i64 as u64); 526 | StopReason::Next 527 | } 528 | RvInsn::Sraiw(a) => { 529 | let v = self.gx(a.rs1) as i32 >> a.shamt; 530 | self.sx(a.rd, v as i64 as u64); 531 | StopReason::Next 532 | } 533 | RvInsn::Addw(a) => { 534 | let v = self.gx(a.rs1) as i32 + self.gx(a.rs2) as i32; 535 | self.sx(a.rd, v as i64 as u64); 536 | StopReason::Next 537 | } 538 | RvInsn::Subw(a) => { 539 | let v = self.gx(a.rs1) as i32 - self.gx(a.rs2) as i32; 540 | self.sx(a.rd, v as i64 as u64); 541 | StopReason::Next 542 | } 543 | RvInsn::Sllw(a) => { 544 | let v = (self.gx(a.rs1) as u32) << (self.gx(a.rs2) & 31); 545 | self.sx(a.rd, v as i32 as i64 as u64); 546 | StopReason::Next 547 | } 548 | RvInsn::Srlw(a) => { 549 | let v = self.gx(a.rs1) as u32 >> (self.gx(a.rs2) & 31); 550 | self.sx(a.rd, v as i32 as i64 as u64); 551 | StopReason::Next 552 | } 553 | RvInsn::Sraw(a) => { 554 | let v = self.gx(a.rs1) as i32 >> (self.gx(a.rs2) & 31); 555 | self.sx(a.rd, v as i64 as u64); 556 | StopReason::Next 557 | } 558 | RvInsn::Mul(a) => { 559 | let v1 = self.gx(a.rs1) as i64; 560 | let v2 = self.gx(a.rs2) as i64; 561 | self.sx(a.rd, v1.wrapping_mul(v2) as u64); 562 | StopReason::Next 563 | } 564 | RvInsn::Mulh(a) => { 565 | let v1 = self.gx(a.rs1) as i64 as i128; 566 | let v2 = self.gx(a.rs2) as i64 as i128; 567 | let v = (v1 * v2) >> 64; 568 | self.sx(a.rd, v as u64); 569 | StopReason::Next 570 | } 571 | RvInsn::Mulhsu(a) => { 572 | let v1 = self.gx(a.rs1) as i64 as i128; 573 | let v2 = self.gx(a.rs1) as u64 as i128; 574 | let v = (v1 * v2) >> 64; 575 | self.sx(a.rd, v as u64); 576 | StopReason::Next 577 | } 578 | RvInsn::Mulhu(a) => { 579 | let v1 = self.gx(a.rs1); 580 | let v2 = self.gx(a.rs2); 581 | // let (_, v) = v1.widening_mul(v2); 582 | let v = (v1 as u128 * v2 as u128) >> 64; 583 | self.sx(a.rd, v as u64); 584 | StopReason::Next 585 | } 586 | RvInsn::Div(a) => { 587 | let v1 = self.gx(a.rs1) as i64; 588 | let v2 = self.gx(a.rs2) as i64; 589 | self.sx(a.rd, v1.wrapping_div(v2) as u64); 590 | StopReason::Next 591 | } 592 | RvInsn::Divu(a) => { 593 | let v1 = self.gx(a.rs1); 594 | let v2 = self.gx(a.rs2); 595 | self.sx(a.rd, v1.wrapping_div(v2)); 596 | StopReason::Next 597 | } 598 | RvInsn::Rem(a) => { 599 | let v1 = self.gx(a.rs1) as i64; 600 | let v2 = self.gx(a.rs2) as i64; 601 | self.sx(a.rd, v1.wrapping_rem(v2) as u64); 602 | StopReason::Next 603 | } 604 | RvInsn::Remu(a) => { 605 | let v1 = self.gx(a.rs1); 606 | let v2 = self.gx(a.rs2); 607 | self.sx(a.rd, v1.wrapping_rem(v2)); 608 | StopReason::Next 609 | } 610 | RvInsn::Mulw(a) => { 611 | let v1 = self.gx(a.rs1) as i32; 612 | let v2 = self.gx(a.rs2) as i32; 613 | self.sx(a.rd, v1.wrapping_mul(v2) as i64 as u64); 614 | StopReason::Next 615 | } 616 | RvInsn::Divw(a) => { 617 | let v1 = self.gx(a.rs1) as i32; 618 | let v2 = self.gx(a.rs2) as i32; 619 | self.sx(a.rd, v1.wrapping_div(v2) as i64 as u64); 620 | StopReason::Next 621 | } 622 | RvInsn::Divuw(a) => { 623 | let v1 = self.gx(a.rs1) as u32; 624 | let v2 = self.gx(a.rs2) as u32; 625 | self.sx(a.rd, v1.wrapping_div(v2) as u64); 626 | StopReason::Next 627 | } 628 | RvInsn::Remw(a) => { 629 | let v1 = self.gx(a.rs1) as i32; 630 | let v2 = self.gx(a.rs2) as i32; 631 | self.sx(a.rd, v1.wrapping_rem(v2) as i64 as u64); 632 | StopReason::Next 633 | } 634 | RvInsn::Remuw(a) => { 635 | let v1 = self.gx(a.rs1) as u32; 636 | let v2 = self.gx(a.rs2) as u32; 637 | self.sx(a.rd, v1.wrapping_rem(v2) as u64); 638 | StopReason::Next 639 | } 640 | RvInsn::LrW(_) => todo!(), 641 | RvInsn::ScW(_) => todo!(), 642 | RvInsn::AmoSwapW(_) => todo!(), 643 | RvInsn::AmoAddW(_) => todo!(), 644 | RvInsn::AmoXorW(_) => todo!(), 645 | RvInsn::AmoAndW(_) => todo!(), 646 | RvInsn::AmoOrW(_) => todo!(), 647 | RvInsn::AmoMinW(_) => todo!(), 648 | RvInsn::AmoMaxW(_) => todo!(), 649 | RvInsn::AmoMinuW(_) => todo!(), 650 | RvInsn::AmoMaxuW(_) => todo!(), 651 | RvInsn::LrD(_) => todo!(), 652 | RvInsn::ScD(_) => todo!(), 653 | RvInsn::AmoSwapD(_) => todo!(), 654 | RvInsn::AmoAddD(_) => todo!(), 655 | RvInsn::AmoXorD(_) => todo!(), 656 | RvInsn::AmoAndD(_) => todo!(), 657 | RvInsn::AmoOrD(_) => todo!(), 658 | RvInsn::AmoMinD(_) => todo!(), 659 | RvInsn::AmoMaxD(_) => todo!(), 660 | RvInsn::AmoMinuD(_) => todo!(), 661 | RvInsn::AmoMaxuD(_) => todo!(), 662 | RvInsn::Flw(a) => { 663 | let addr = (self.gx(a.rs1) as i64 + a.imm as i64) as u64; 664 | match self.get_u32(addr.into()) { 665 | Ok(v) => { 666 | self.sf32(a.rd, v as f32); 667 | StopReason::Next 668 | } 669 | Err(e) => e, 670 | } 671 | } 672 | RvInsn::Fsw(a) => { 673 | let addr = (self.gx(a.rs1) as i64 + a.imm as i64) as u64; 674 | self.set_u32(addr.into(), self.gf32(a.rs2) as u32) 675 | .err() 676 | .unwrap_or(StopReason::Next) 677 | } 678 | RvInsn::FmaddS(_) => todo!(), 679 | RvInsn::FmsubS(_) => todo!(), 680 | RvInsn::FnmsubS(_) => todo!(), 681 | RvInsn::FnmaddS(_) => todo!(), 682 | RvInsn::FaddS(_) => todo!(), 683 | RvInsn::FsubS(_) => todo!(), 684 | RvInsn::FmulS(_) => todo!(), 685 | RvInsn::FdivS(_) => todo!(), 686 | RvInsn::FsqrtS(_) => todo!(), 687 | RvInsn::FsgnjS(_) => todo!(), 688 | RvInsn::FsgnjnS(_) => todo!(), 689 | RvInsn::FsgnjxS(_) => todo!(), 690 | RvInsn::FminS(_) => todo!(), 691 | RvInsn::FmaxS(_) => todo!(), 692 | RvInsn::FcvtWS(_) => todo!(), 693 | RvInsn::FcvtWuS(_) => todo!(), 694 | RvInsn::FmvXW(a) => { 695 | self.sx(a.rd, self.gf32(a.rs1) as i32 as i64 as u64); 696 | StopReason::Next 697 | } 698 | RvInsn::FeqS(_) => todo!(), 699 | RvInsn::FltS(_) => todo!(), 700 | RvInsn::FleS(_) => todo!(), 701 | RvInsn::FclassS(_) => todo!(), 702 | RvInsn::FcvtSW(_) => todo!(), 703 | RvInsn::FcvtSWu(_) => todo!(), 704 | RvInsn::FmvWX(a) => { 705 | self.sf32(a.rd, self.gx(a.rs1) as u32 as f32); 706 | StopReason::Next 707 | } 708 | RvInsn::FcvtLS(_) => todo!(), 709 | RvInsn::FcvtLuS(_) => todo!(), 710 | RvInsn::FcvtSL(_) => todo!(), 711 | RvInsn::FcvtSLu(_) => todo!(), 712 | RvInsn::Fld(a) => { 713 | let addr = (self.gx(a.rs1) as i64 + a.imm as i64) as u64; 714 | match self.get_u64(addr.into()) { 715 | Ok(v) => { 716 | self.sf64(a.rd, v as f64); 717 | StopReason::Next 718 | } 719 | Err(e) => e, 720 | } 721 | } 722 | RvInsn::Fsd(a) => { 723 | let addr = (self.gx(a.rs1) as i64 + a.imm as i64) as u64; 724 | self.set_u64(addr.into(), self.gf64(a.rs2) as u64) 725 | .err() 726 | .unwrap_or(StopReason::Next) 727 | } 728 | RvInsn::FmaddD(_) => todo!(), 729 | RvInsn::FmsubD(_) => todo!(), 730 | RvInsn::FnmsubD(_) => todo!(), 731 | RvInsn::FnmaddD(_) => todo!(), 732 | RvInsn::FaddD(_) => todo!(), 733 | RvInsn::FsubD(_) => todo!(), 734 | RvInsn::FmulD(_) => todo!(), 735 | RvInsn::FdivD(_) => todo!(), 736 | RvInsn::FsqrtD(_) => todo!(), 737 | RvInsn::FsgnjD(_) => todo!(), 738 | RvInsn::FsgnjnD(_) => todo!(), 739 | RvInsn::FsgnjxD(_) => todo!(), 740 | RvInsn::FminD(_) => todo!(), 741 | RvInsn::FmaxD(_) => todo!(), 742 | RvInsn::FcvtSD(_) => todo!(), 743 | RvInsn::FcvtDS(_) => todo!(), 744 | RvInsn::FeqD(_) => todo!(), 745 | RvInsn::FltD(_) => todo!(), 746 | RvInsn::FleD(_) => todo!(), 747 | RvInsn::FclassD(_) => todo!(), 748 | RvInsn::FcvtWD(_) => todo!(), 749 | RvInsn::FcvtWuD(_) => todo!(), 750 | RvInsn::FcvtDW(_) => todo!(), 751 | RvInsn::FcvtDWu(_) => todo!(), 752 | RvInsn::FcvtLD(_) => todo!(), 753 | RvInsn::FcvtLuD(_) => todo!(), 754 | RvInsn::FmvXD(a) => { 755 | self.sx(a.rd, self.gf64(a.rs1) as u64); 756 | StopReason::Next 757 | } 758 | RvInsn::FcvtDL(_) => todo!(), 759 | RvInsn::FcvtDLu(_) => todo!(), 760 | RvInsn::FmvDX(a) => { 761 | self.sf64(a.rd, self.gx(a.rs1) as f64); 762 | StopReason::Next 763 | } 764 | } 765 | } 766 | } 767 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU General Public License is a free, copyleft license for 11 | software and other kinds of works. 12 | 13 | The licenses for most software and other practical works are designed 14 | to take away your freedom to share and change the works. By contrast, 15 | the GNU General Public License is intended to guarantee your freedom to 16 | share and change all versions of a program--to make sure it remains free 17 | software for all its users. We, the Free Software Foundation, use the 18 | GNU General Public License for most of our software; it applies also to 19 | any other work released this way by its authors. You can apply it to 20 | your programs, too. 21 | 22 | When we speak of free software, we are referring to freedom, not 23 | price. Our General Public Licenses are designed to make sure that you 24 | have the freedom to distribute copies of free software (and charge for 25 | them if you wish), that you receive source code or can get it if you 26 | want it, that you can change the software or use pieces of it in new 27 | free programs, and that you know you can do these things. 28 | 29 | To protect your rights, we need to prevent others from denying you 30 | these rights or asking you to surrender the rights. Therefore, you have 31 | certain responsibilities if you distribute copies of the software, or if 32 | you modify it: responsibilities to respect the freedom of others. 33 | 34 | For example, if you distribute copies of such a program, whether 35 | gratis or for a fee, you must pass on to the recipients the same 36 | freedoms that you received. You must make sure that they, too, receive 37 | or can get the source code. And you must show them these terms so they 38 | know their rights. 39 | 40 | Developers that use the GNU GPL protect your rights with two steps: 41 | (1) assert copyright on the software, and (2) offer you this License 42 | giving you legal permission to copy, distribute and/or modify it. 43 | 44 | For the developers' and authors' protection, the GPL clearly explains 45 | that there is no warranty for this free software. For both users' and 46 | authors' sake, the GPL requires that modified versions be marked as 47 | changed, so that their problems will not be attributed erroneously to 48 | authors of previous versions. 49 | 50 | Some devices are designed to deny users access to install or run 51 | modified versions of the software inside them, although the manufacturer 52 | can do so. This is fundamentally incompatible with the aim of 53 | protecting users' freedom to change the software. The systematic 54 | pattern of such abuse occurs in the area of products for individuals to 55 | use, which is precisely where it is most unacceptable. Therefore, we 56 | have designed this version of the GPL to prohibit the practice for those 57 | products. If such problems arise substantially in other domains, we 58 | stand ready to extend this provision to those domains in future versions 59 | of the GPL, as needed to protect the freedom of users. 60 | 61 | Finally, every program is threatened constantly by software patents. 62 | States should not allow patents to restrict development and use of 63 | software on general-purpose computers, but in those that do, we wish to 64 | avoid the special danger that patents applied to a free program could 65 | make it effectively proprietary. To prevent this, the GPL assures that 66 | patents cannot be used to render the program non-free. 67 | 68 | The precise terms and conditions for copying, distribution and 69 | modification follow. 70 | 71 | TERMS AND CONDITIONS 72 | 73 | 0. Definitions. 74 | 75 | "This License" refers to version 3 of the GNU General Public License. 76 | 77 | "Copyright" also means copyright-like laws that apply to other kinds of 78 | works, such as semiconductor masks. 79 | 80 | "The Program" refers to any copyrightable work licensed under this 81 | License. Each licensee is addressed as "you". "Licensees" and 82 | "recipients" may be individuals or organizations. 83 | 84 | To "modify" a work means to copy from or adapt all or part of the work 85 | in a fashion requiring copyright permission, other than the making of an 86 | exact copy. The resulting work is called a "modified version" of the 87 | earlier work or a work "based on" the earlier work. 88 | 89 | A "covered work" means either the unmodified Program or a work based 90 | on the Program. 91 | 92 | To "propagate" a work means to do anything with it that, without 93 | permission, would make you directly or secondarily liable for 94 | infringement under applicable copyright law, except executing it on a 95 | computer or modifying a private copy. Propagation includes copying, 96 | distribution (with or without modification), making available to the 97 | public, and in some countries other activities as well. 98 | 99 | To "convey" a work means any kind of propagation that enables other 100 | parties to make or receive copies. Mere interaction with a user through 101 | a computer network, with no transfer of a copy, is not conveying. 102 | 103 | An interactive user interface displays "Appropriate Legal Notices" 104 | to the extent that it includes a convenient and prominently visible 105 | feature that (1) displays an appropriate copyright notice, and (2) 106 | tells the user that there is no warranty for the work (except to the 107 | extent that warranties are provided), that licensees may convey the 108 | work under this License, and how to view a copy of this License. If 109 | the interface presents a list of user commands or options, such as a 110 | menu, a prominent item in the list meets this criterion. 111 | 112 | 1. Source Code. 113 | 114 | The "source code" for a work means the preferred form of the work 115 | for making modifications to it. "Object code" means any non-source 116 | form of a work. 117 | 118 | A "Standard Interface" means an interface that either is an official 119 | standard defined by a recognized standards body, or, in the case of 120 | interfaces specified for a particular programming language, one that 121 | is widely used among developers working in that language. 122 | 123 | The "System Libraries" of an executable work include anything, other 124 | than the work as a whole, that (a) is included in the normal form of 125 | packaging a Major Component, but which is not part of that Major 126 | Component, and (b) serves only to enable use of the work with that 127 | Major Component, or to implement a Standard Interface for which an 128 | implementation is available to the public in source code form. A 129 | "Major Component", in this context, means a major essential component 130 | (kernel, window system, and so on) of the specific operating system 131 | (if any) on which the executable work runs, or a compiler used to 132 | produce the work, or an object code interpreter used to run it. 133 | 134 | The "Corresponding Source" for a work in object code form means all 135 | the source code needed to generate, install, and (for an executable 136 | work) run the object code and to modify the work, including scripts to 137 | control those activities. However, it does not include the work's 138 | System Libraries, or general-purpose tools or generally available free 139 | programs which are used unmodified in performing those activities but 140 | which are not part of the work. For example, Corresponding Source 141 | includes interface definition files associated with source files for 142 | the work, and the source code for shared libraries and dynamically 143 | linked subprograms that the work is specifically designed to require, 144 | such as by intimate data communication or control flow between those 145 | subprograms and other parts of the work. 146 | 147 | The Corresponding Source need not include anything that users 148 | can regenerate automatically from other parts of the Corresponding 149 | Source. 150 | 151 | The Corresponding Source for a work in source code form is that 152 | same work. 153 | 154 | 2. Basic Permissions. 155 | 156 | All rights granted under this License are granted for the term of 157 | copyright on the Program, and are irrevocable provided the stated 158 | conditions are met. This License explicitly affirms your unlimited 159 | permission to run the unmodified Program. The output from running a 160 | covered work is covered by this License only if the output, given its 161 | content, constitutes a covered work. This License acknowledges your 162 | rights of fair use or other equivalent, as provided by copyright law. 163 | 164 | You may make, run and propagate covered works that you do not 165 | convey, without conditions so long as your license otherwise remains 166 | in force. You may convey covered works to others for the sole purpose 167 | of having them make modifications exclusively for you, or provide you 168 | with facilities for running those works, provided that you comply with 169 | the terms of this License in conveying all material for which you do 170 | not control copyright. Those thus making or running the covered works 171 | for you must do so exclusively on your behalf, under your direction 172 | and control, on terms that prohibit them from making any copies of 173 | your copyrighted material outside their relationship with you. 174 | 175 | Conveying under any other circumstances is permitted solely under 176 | the conditions stated below. Sublicensing is not allowed; section 10 177 | makes it unnecessary. 178 | 179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 180 | 181 | No covered work shall be deemed part of an effective technological 182 | measure under any applicable law fulfilling obligations under article 183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 184 | similar laws prohibiting or restricting circumvention of such 185 | measures. 186 | 187 | When you convey a covered work, you waive any legal power to forbid 188 | circumvention of technological measures to the extent such circumvention 189 | is effected by exercising rights under this License with respect to 190 | the covered work, and you disclaim any intention to limit operation or 191 | modification of the work as a means of enforcing, against the work's 192 | users, your or third parties' legal rights to forbid circumvention of 193 | technological measures. 194 | 195 | 4. Conveying Verbatim Copies. 196 | 197 | You may convey verbatim copies of the Program's source code as you 198 | receive it, in any medium, provided that you conspicuously and 199 | appropriately publish on each copy an appropriate copyright notice; 200 | keep intact all notices stating that this License and any 201 | non-permissive terms added in accord with section 7 apply to the code; 202 | keep intact all notices of the absence of any warranty; and give all 203 | recipients a copy of this License along with the Program. 204 | 205 | You may charge any price or no price for each copy that you convey, 206 | and you may offer support or warranty protection for a fee. 207 | 208 | 5. Conveying Modified Source Versions. 209 | 210 | You may convey a work based on the Program, or the modifications to 211 | produce it from the Program, in the form of source code under the 212 | terms of section 4, provided that you also meet all of these conditions: 213 | 214 | a) The work must carry prominent notices stating that you modified 215 | it, and giving a relevant date. 216 | 217 | b) The work must carry prominent notices stating that it is 218 | released under this License and any conditions added under section 219 | 7. This requirement modifies the requirement in section 4 to 220 | "keep intact all notices". 221 | 222 | c) You must license the entire work, as a whole, under this 223 | License to anyone who comes into possession of a copy. This 224 | License will therefore apply, along with any applicable section 7 225 | additional terms, to the whole of the work, and all its parts, 226 | regardless of how they are packaged. This License gives no 227 | permission to license the work in any other way, but it does not 228 | invalidate such permission if you have separately received it. 229 | 230 | d) If the work has interactive user interfaces, each must display 231 | Appropriate Legal Notices; however, if the Program has interactive 232 | interfaces that do not display Appropriate Legal Notices, your 233 | work need not make them do so. 234 | 235 | A compilation of a covered work with other separate and independent 236 | works, which are not by their nature extensions of the covered work, 237 | and which are not combined with it such as to form a larger program, 238 | in or on a volume of a storage or distribution medium, is called an 239 | "aggregate" if the compilation and its resulting copyright are not 240 | used to limit the access or legal rights of the compilation's users 241 | beyond what the individual works permit. Inclusion of a covered work 242 | in an aggregate does not cause this License to apply to the other 243 | parts of the aggregate. 244 | 245 | 6. Conveying Non-Source Forms. 246 | 247 | You may convey a covered work in object code form under the terms 248 | of sections 4 and 5, provided that you also convey the 249 | machine-readable Corresponding Source under the terms of this License, 250 | in one of these ways: 251 | 252 | a) Convey the object code in, or embodied in, a physical product 253 | (including a physical distribution medium), accompanied by the 254 | Corresponding Source fixed on a durable physical medium 255 | customarily used for software interchange. 256 | 257 | b) Convey the object code in, or embodied in, a physical product 258 | (including a physical distribution medium), accompanied by a 259 | written offer, valid for at least three years and valid for as 260 | long as you offer spare parts or customer support for that product 261 | model, to give anyone who possesses the object code either (1) a 262 | copy of the Corresponding Source for all the software in the 263 | product that is covered by this License, on a durable physical 264 | medium customarily used for software interchange, for a price no 265 | more than your reasonable cost of physically performing this 266 | conveying of source, or (2) access to copy the 267 | Corresponding Source from a network server at no charge. 268 | 269 | c) Convey individual copies of the object code with a copy of the 270 | written offer to provide the Corresponding Source. This 271 | alternative is allowed only occasionally and noncommercially, and 272 | only if you received the object code with such an offer, in accord 273 | with subsection 6b. 274 | 275 | d) Convey the object code by offering access from a designated 276 | place (gratis or for a charge), and offer equivalent access to the 277 | Corresponding Source in the same way through the same place at no 278 | further charge. You need not require recipients to copy the 279 | Corresponding Source along with the object code. If the place to 280 | copy the object code is a network server, the Corresponding Source 281 | may be on a different server (operated by you or a third party) 282 | that supports equivalent copying facilities, provided you maintain 283 | clear directions next to the object code saying where to find the 284 | Corresponding Source. Regardless of what server hosts the 285 | Corresponding Source, you remain obligated to ensure that it is 286 | available for as long as needed to satisfy these requirements. 287 | 288 | e) Convey the object code using peer-to-peer transmission, provided 289 | you inform other peers where the object code and Corresponding 290 | Source of the work are being offered to the general public at no 291 | charge under subsection 6d. 292 | 293 | A separable portion of the object code, whose source code is excluded 294 | from the Corresponding Source as a System Library, need not be 295 | included in conveying the object code work. 296 | 297 | A "User Product" is either (1) a "consumer product", which means any 298 | tangible personal property which is normally used for personal, family, 299 | or household purposes, or (2) anything designed or sold for incorporation 300 | into a dwelling. In determining whether a product is a consumer product, 301 | doubtful cases shall be resolved in favor of coverage. For a particular 302 | product received by a particular user, "normally used" refers to a 303 | typical or common use of that class of product, regardless of the status 304 | of the particular user or of the way in which the particular user 305 | actually uses, or expects or is expected to use, the product. A product 306 | is a consumer product regardless of whether the product has substantial 307 | commercial, industrial or non-consumer uses, unless such uses represent 308 | the only significant mode of use of the product. 309 | 310 | "Installation Information" for a User Product means any methods, 311 | procedures, authorization keys, or other information required to install 312 | and execute modified versions of a covered work in that User Product from 313 | a modified version of its Corresponding Source. The information must 314 | suffice to ensure that the continued functioning of the modified object 315 | code is in no case prevented or interfered with solely because 316 | modification has been made. 317 | 318 | If you convey an object code work under this section in, or with, or 319 | specifically for use in, a User Product, and the conveying occurs as 320 | part of a transaction in which the right of possession and use of the 321 | User Product is transferred to the recipient in perpetuity or for a 322 | fixed term (regardless of how the transaction is characterized), the 323 | Corresponding Source conveyed under this section must be accompanied 324 | by the Installation Information. But this requirement does not apply 325 | if neither you nor any third party retains the ability to install 326 | modified object code on the User Product (for example, the work has 327 | been installed in ROM). 328 | 329 | The requirement to provide Installation Information does not include a 330 | requirement to continue to provide support service, warranty, or updates 331 | for a work that has been modified or installed by the recipient, or for 332 | the User Product in which it has been modified or installed. Access to a 333 | network may be denied when the modification itself materially and 334 | adversely affects the operation of the network or violates the rules and 335 | protocols for communication across the network. 336 | 337 | Corresponding Source conveyed, and Installation Information provided, 338 | in accord with this section must be in a format that is publicly 339 | documented (and with an implementation available to the public in 340 | source code form), and must require no special password or key for 341 | unpacking, reading or copying. 342 | 343 | 7. Additional Terms. 344 | 345 | "Additional permissions" are terms that supplement the terms of this 346 | License by making exceptions from one or more of its conditions. 347 | Additional permissions that are applicable to the entire Program shall 348 | be treated as though they were included in this License, to the extent 349 | that they are valid under applicable law. If additional permissions 350 | apply only to part of the Program, that part may be used separately 351 | under those permissions, but the entire Program remains governed by 352 | this License without regard to the additional permissions. 353 | 354 | When you convey a copy of a covered work, you may at your option 355 | remove any additional permissions from that copy, or from any part of 356 | it. (Additional permissions may be written to require their own 357 | removal in certain cases when you modify the work.) You may place 358 | additional permissions on material, added by you to a covered work, 359 | for which you have or can give appropriate copyright permission. 360 | 361 | Notwithstanding any other provision of this License, for material you 362 | add to a covered work, you may (if authorized by the copyright holders of 363 | that material) supplement the terms of this License with terms: 364 | 365 | a) Disclaiming warranty or limiting liability differently from the 366 | terms of sections 15 and 16 of this License; or 367 | 368 | b) Requiring preservation of specified reasonable legal notices or 369 | author attributions in that material or in the Appropriate Legal 370 | Notices displayed by works containing it; or 371 | 372 | c) Prohibiting misrepresentation of the origin of that material, or 373 | requiring that modified versions of such material be marked in 374 | reasonable ways as different from the original version; or 375 | 376 | d) Limiting the use for publicity purposes of names of licensors or 377 | authors of the material; or 378 | 379 | e) Declining to grant rights under trademark law for use of some 380 | trade names, trademarks, or service marks; or 381 | 382 | f) Requiring indemnification of licensors and authors of that 383 | material by anyone who conveys the material (or modified versions of 384 | it) with contractual assumptions of liability to the recipient, for 385 | any liability that these contractual assumptions directly impose on 386 | those licensors and authors. 387 | 388 | All other non-permissive additional terms are considered "further 389 | restrictions" within the meaning of section 10. If the Program as you 390 | received it, or any part of it, contains a notice stating that it is 391 | governed by this License along with a term that is a further 392 | restriction, you may remove that term. If a license document contains 393 | a further restriction but permits relicensing or conveying under this 394 | License, you may add to a covered work material governed by the terms 395 | of that license document, provided that the further restriction does 396 | not survive such relicensing or conveying. 397 | 398 | If you add terms to a covered work in accord with this section, you 399 | must place, in the relevant source files, a statement of the 400 | additional terms that apply to those files, or a notice indicating 401 | where to find the applicable terms. 402 | 403 | Additional terms, permissive or non-permissive, may be stated in the 404 | form of a separately written license, or stated as exceptions; 405 | the above requirements apply either way. 406 | 407 | 8. Termination. 408 | 409 | You may not propagate or modify a covered work except as expressly 410 | provided under this License. Any attempt otherwise to propagate or 411 | modify it is void, and will automatically terminate your rights under 412 | this License (including any patent licenses granted under the third 413 | paragraph of section 11). 414 | 415 | However, if you cease all violation of this License, then your 416 | license from a particular copyright holder is reinstated (a) 417 | provisionally, unless and until the copyright holder explicitly and 418 | finally terminates your license, and (b) permanently, if the copyright 419 | holder fails to notify you of the violation by some reasonable means 420 | prior to 60 days after the cessation. 421 | 422 | Moreover, your license from a particular copyright holder is 423 | reinstated permanently if the copyright holder notifies you of the 424 | violation by some reasonable means, this is the first time you have 425 | received notice of violation of this License (for any work) from that 426 | copyright holder, and you cure the violation prior to 30 days after 427 | your receipt of the notice. 428 | 429 | Termination of your rights under this section does not terminate the 430 | licenses of parties who have received copies or rights from you under 431 | this License. If your rights have been terminated and not permanently 432 | reinstated, you do not qualify to receive new licenses for the same 433 | material under section 10. 434 | 435 | 9. Acceptance Not Required for Having Copies. 436 | 437 | You are not required to accept this License in order to receive or 438 | run a copy of the Program. Ancillary propagation of a covered work 439 | occurring solely as a consequence of using peer-to-peer transmission 440 | to receive a copy likewise does not require acceptance. However, 441 | nothing other than this License grants you permission to propagate or 442 | modify any covered work. These actions infringe copyright if you do 443 | not accept this License. Therefore, by modifying or propagating a 444 | covered work, you indicate your acceptance of this License to do so. 445 | 446 | 10. Automatic Licensing of Downstream Recipients. 447 | 448 | Each time you convey a covered work, the recipient automatically 449 | receives a license from the original licensors, to run, modify and 450 | propagate that work, subject to this License. You are not responsible 451 | for enforcing compliance by third parties with this License. 452 | 453 | An "entity transaction" is a transaction transferring control of an 454 | organization, or substantially all assets of one, or subdividing an 455 | organization, or merging organizations. If propagation of a covered 456 | work results from an entity transaction, each party to that 457 | transaction who receives a copy of the work also receives whatever 458 | licenses to the work the party's predecessor in interest had or could 459 | give under the previous paragraph, plus a right to possession of the 460 | Corresponding Source of the work from the predecessor in interest, if 461 | the predecessor has it or can get it with reasonable efforts. 462 | 463 | You may not impose any further restrictions on the exercise of the 464 | rights granted or affirmed under this License. For example, you may 465 | not impose a license fee, royalty, or other charge for exercise of 466 | rights granted under this License, and you may not initiate litigation 467 | (including a cross-claim or counterclaim in a lawsuit) alleging that 468 | any patent claim is infringed by making, using, selling, offering for 469 | sale, or importing the Program or any portion of it. 470 | 471 | 11. Patents. 472 | 473 | A "contributor" is a copyright holder who authorizes use under this 474 | License of the Program or a work on which the Program is based. The 475 | work thus licensed is called the contributor's "contributor version". 476 | 477 | A contributor's "essential patent claims" are all patent claims 478 | owned or controlled by the contributor, whether already acquired or 479 | hereafter acquired, that would be infringed by some manner, permitted 480 | by this License, of making, using, or selling its contributor version, 481 | but do not include claims that would be infringed only as a 482 | consequence of further modification of the contributor version. For 483 | purposes of this definition, "control" includes the right to grant 484 | patent sublicenses in a manner consistent with the requirements of 485 | this License. 486 | 487 | Each contributor grants you a non-exclusive, worldwide, royalty-free 488 | patent license under the contributor's essential patent claims, to 489 | make, use, sell, offer for sale, import and otherwise run, modify and 490 | propagate the contents of its contributor version. 491 | 492 | In the following three paragraphs, a "patent license" is any express 493 | agreement or commitment, however denominated, not to enforce a patent 494 | (such as an express permission to practice a patent or covenant not to 495 | sue for patent infringement). To "grant" such a patent license to a 496 | party means to make such an agreement or commitment not to enforce a 497 | patent against the party. 498 | 499 | If you convey a covered work, knowingly relying on a patent license, 500 | and the Corresponding Source of the work is not available for anyone 501 | to copy, free of charge and under the terms of this License, through a 502 | publicly available network server or other readily accessible means, 503 | then you must either (1) cause the Corresponding Source to be so 504 | available, or (2) arrange to deprive yourself of the benefit of the 505 | patent license for this particular work, or (3) arrange, in a manner 506 | consistent with the requirements of this License, to extend the patent 507 | license to downstream recipients. "Knowingly relying" means you have 508 | actual knowledge that, but for the patent license, your conveying the 509 | covered work in a country, or your recipient's use of the covered work 510 | in a country, would infringe one or more identifiable patents in that 511 | country that you have reason to believe are valid. 512 | 513 | If, pursuant to or in connection with a single transaction or 514 | arrangement, you convey, or propagate by procuring conveyance of, a 515 | covered work, and grant a patent license to some of the parties 516 | receiving the covered work authorizing them to use, propagate, modify 517 | or convey a specific copy of the covered work, then the patent license 518 | you grant is automatically extended to all recipients of the covered 519 | work and works based on it. 520 | 521 | A patent license is "discriminatory" if it does not include within 522 | the scope of its coverage, prohibits the exercise of, or is 523 | conditioned on the non-exercise of one or more of the rights that are 524 | specifically granted under this License. You may not convey a covered 525 | work if you are a party to an arrangement with a third party that is 526 | in the business of distributing software, under which you make payment 527 | to the third party based on the extent of your activity of conveying 528 | the work, and under which the third party grants, to any of the 529 | parties who would receive the covered work from you, a discriminatory 530 | patent license (a) in connection with copies of the covered work 531 | conveyed by you (or copies made from those copies), or (b) primarily 532 | for and in connection with specific products or compilations that 533 | contain the covered work, unless you entered into that arrangement, 534 | or that patent license was granted, prior to 28 March 2007. 535 | 536 | Nothing in this License shall be construed as excluding or limiting 537 | any implied license or other defenses to infringement that may 538 | otherwise be available to you under applicable patent law. 539 | 540 | 12. No Surrender of Others' Freedom. 541 | 542 | If conditions are imposed on you (whether by court order, agreement or 543 | otherwise) that contradict the conditions of this License, they do not 544 | excuse you from the conditions of this License. If you cannot convey a 545 | covered work so as to satisfy simultaneously your obligations under this 546 | License and any other pertinent obligations, then as a consequence you may 547 | not convey it at all. For example, if you agree to terms that obligate you 548 | to collect a royalty for further conveying from those to whom you convey 549 | the Program, the only way you could satisfy both those terms and this 550 | License would be to refrain entirely from conveying the Program. 551 | 552 | 13. Use with the GNU Affero General Public License. 553 | 554 | Notwithstanding any other provision of this License, you have 555 | permission to link or combine any covered work with a work licensed 556 | under version 3 of the GNU Affero General Public License into a single 557 | combined work, and to convey the resulting work. The terms of this 558 | License will continue to apply to the part which is the covered work, 559 | but the special requirements of the GNU Affero General Public License, 560 | section 13, concerning interaction through a network will apply to the 561 | combination as such. 562 | 563 | 14. Revised Versions of this License. 564 | 565 | The Free Software Foundation may publish revised and/or new versions of 566 | the GNU General Public License from time to time. Such new versions will 567 | be similar in spirit to the present version, but may differ in detail to 568 | address new problems or concerns. 569 | 570 | Each version is given a distinguishing version number. If the 571 | Program specifies that a certain numbered version of the GNU General 572 | Public License "or any later version" applies to it, you have the 573 | option of following the terms and conditions either of that numbered 574 | version or of any later version published by the Free Software 575 | Foundation. If the Program does not specify a version number of the 576 | GNU General Public License, you may choose any version ever published 577 | by the Free Software Foundation. 578 | 579 | If the Program specifies that a proxy can decide which future 580 | versions of the GNU General Public License can be used, that proxy's 581 | public statement of acceptance of a version permanently authorizes you 582 | to choose that version for the Program. 583 | 584 | Later license versions may give you additional or different 585 | permissions. However, no additional obligations are imposed on any 586 | author or copyright holder as a result of your choosing to follow a 587 | later version. 588 | 589 | 15. Disclaimer of Warranty. 590 | 591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 599 | 600 | 16. Limitation of Liability. 601 | 602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 610 | SUCH DAMAGES. 611 | 612 | 17. Interpretation of Sections 15 and 16. 613 | 614 | If the disclaimer of warranty and limitation of liability provided 615 | above cannot be given local legal effect according to their terms, 616 | reviewing courts shall apply local law that most closely approximates 617 | an absolute waiver of all civil liability in connection with the 618 | Program, unless a warranty or assumption of liability accompanies a 619 | copy of the Program in return for a fee. 620 | 621 | END OF TERMS AND CONDITIONS 622 | 623 | How to Apply These Terms to Your New Programs 624 | 625 | If you develop a new program, and you want it to be of the greatest 626 | possible use to the public, the best way to achieve this is to make it 627 | free software which everyone can redistribute and change under these terms. 628 | 629 | To do so, attach the following notices to the program. It is safest 630 | to attach them to the start of each source file to most effectively 631 | state the exclusion of warranty; and each file should have at least 632 | the "copyright" line and a pointer to where the full notice is found. 633 | 634 | 635 | Copyright (C) 636 | 637 | This program is free software: you can redistribute it and/or modify 638 | it under the terms of the GNU General Public License as published by 639 | the Free Software Foundation, either version 3 of the License, or 640 | (at your option) any later version. 641 | 642 | This program is distributed in the hope that it will be useful, 643 | but WITHOUT ANY WARRANTY; without even the implied warranty of 644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 645 | GNU General Public License for more details. 646 | 647 | You should have received a copy of the GNU General Public License 648 | along with this program. If not, see . 649 | 650 | Also add information on how to contact you by electronic and paper mail. 651 | 652 | If the program does terminal interaction, make it output a short 653 | notice like this when it starts in an interactive mode: 654 | 655 | Copyright (C) 656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 657 | This is free software, and you are welcome to redistribute it 658 | under certain conditions; type `show c' for details. 659 | 660 | The hypothetical commands `show w' and `show c' should show the appropriate 661 | parts of the General Public License. Of course, your program's commands 662 | might be different; for a GUI interface, you would use an "about box". 663 | 664 | You should also get your employer (if you work as a programmer) or school, 665 | if any, to sign a "copyright disclaimer" for the program, if necessary. 666 | For more information on this, and how to apply and follow the GNU GPL, see 667 | . 668 | 669 | The GNU General Public License does not permit incorporating your program 670 | into proprietary programs. If your program is a subroutine library, you 671 | may consider it more useful to permit linking proprietary applications with 672 | the library. If this is what you want to do, use the GNU Lesser General 673 | Public License instead of this License. But first, please read 674 | . 675 | --------------------------------------------------------------------------------