#[cfg(has_asm)]
pub mod asm;
pub mod elf_adaptor;
pub mod trace;
use std::fmt::{self, Display};
use std::sync::atomic::{AtomicU8, Ordering};
use std::sync::Arc;
use bytes::Bytes;
use scroll::Pread;
use super::debugger::Debugger;
use super::decoder::{build_decoder, Decoder};
use super::instructions::{execute, Instruction, Register};
use super::memory::{round_page_down, round_page_up, Memory};
use super::syscalls::Syscalls;
use super::{
    registers::{A0, A7, REGISTER_ABI_NAMES, SP},
    Error, ISA_MOP, RISCV_GENERAL_REGISTER_NUMBER, RISCV_MAX_MEMORY,
};
pub const VERSION0: u32 = 0;
pub const VERSION1: u32 = 1;
pub const VERSION2: u32 = 2;
pub trait CoreMachine {
    type REG: Register;
    type MEM: Memory<REG = Self::REG>;
    fn pc(&self) -> &Self::REG;
    fn update_pc(&mut self, pc: Self::REG);
    fn commit_pc(&mut self);
    fn memory(&self) -> &Self::MEM;
    fn memory_mut(&mut self) -> &mut Self::MEM;
    fn registers(&self) -> &[Self::REG];
    fn set_register(&mut self, idx: usize, value: Self::REG);
    fn version(&self) -> u32;
    fn isa(&self) -> u8;
}
pub trait Machine: CoreMachine {
    fn ecall(&mut self) -> Result<(), Error>;
    fn ebreak(&mut self) -> Result<(), Error>;
}
pub trait SupportMachine: CoreMachine {
    fn cycles(&self) -> u64;
    fn set_cycles(&mut self, cycles: u64);
    fn max_cycles(&self) -> u64;
    fn running(&self) -> bool;
    fn set_running(&mut self, running: bool);
    fn reset(&mut self, max_cycles: u64);
    fn reset_signal(&mut self) -> bool;
    fn add_cycles(&mut self, cycles: u64) -> Result<(), Error> {
        let new_cycles = self
            .cycles()
            .checked_add(cycles)
            .ok_or(Error::CyclesOverflow)?;
        if new_cycles > self.max_cycles() {
            return Err(Error::CyclesExceeded);
        }
        self.set_cycles(new_cycles);
        Ok(())
    }
    fn add_cycles_no_checking(&mut self, cycles: u64) -> Result<(), Error> {
        let new_cycles = self
            .cycles()
            .checked_add(cycles)
            .ok_or(Error::CyclesOverflow)?;
        self.set_cycles(new_cycles);
        Ok(())
    }
    fn load_elf_inner(&mut self, program: &Bytes, update_pc: bool) -> Result<u64, Error> {
        let version = self.version();
        let (e_entry, program_headers): (u64, Vec<elf_adaptor::ProgramHeader>) =
            if version < VERSION1 {
                use goblin_v023::container::Ctx;
                use goblin_v023::elf::{program_header::ProgramHeader, Header};
                let header = program.pread::<Header>(0)?;
                let container = header.container().map_err(|_e| Error::ElfBits)?;
                let endianness = header.endianness().map_err(|_e| Error::ElfBits)?;
                if Self::REG::BITS != if container.is_big() { 64 } else { 32 } {
                    return Err(Error::ElfBits);
                }
                let ctx = Ctx::new(container, endianness);
                let program_headers = ProgramHeader::parse(
                    program,
                    header.e_phoff as usize,
                    header.e_phnum as usize,
                    ctx,
                )?
                .iter()
                .map(elf_adaptor::ProgramHeader::from_v0)
                .collect();
                (header.e_entry, program_headers)
            } else {
                use goblin_v040::container::Ctx;
                use goblin_v040::elf::{program_header::ProgramHeader, Header};
                let header = program.pread::<Header>(0)?;
                let container = header.container().map_err(|_e| Error::ElfBits)?;
                let endianness = header.endianness().map_err(|_e| Error::ElfBits)?;
                if Self::REG::BITS != if container.is_big() { 64 } else { 32 } {
                    return Err(Error::ElfBits);
                }
                let ctx = Ctx::new(container, endianness);
                let program_headers = ProgramHeader::parse(
                    program,
                    header.e_phoff as usize,
                    header.e_phnum as usize,
                    ctx,
                )?
                .iter()
                .map(elf_adaptor::ProgramHeader::from_v1)
                .collect();
                (header.e_entry, program_headers)
            };
        let mut bytes: u64 = 0;
        for program_header in program_headers {
            if program_header.p_type == elf_adaptor::PT_LOAD {
                let aligned_start = round_page_down(program_header.p_vaddr);
                let padding_start = program_header.p_vaddr.wrapping_sub(aligned_start);
                let size = round_page_up(program_header.p_memsz.wrapping_add(padding_start));
                let slice_start = program_header.p_offset;
                let slice_end = program_header
                    .p_offset
                    .wrapping_add(program_header.p_filesz);
                if slice_start > slice_end || slice_end > program.len() as u64 {
                    return Err(Error::ElfSegmentAddrOrSizeError);
                }
                self.memory_mut().init_pages(
                    aligned_start,
                    size,
                    elf_adaptor::convert_flags(program_header.p_flags, version < VERSION1)?,
                    Some(program.slice(slice_start as usize..slice_end as usize)),
                    padding_start,
                )?;
                if version < VERSION1 {
                    self.memory_mut()
                        .store_byte(aligned_start, padding_start, 0)?;
                }
                bytes = bytes.checked_add(slice_end - slice_start).ok_or_else(|| {
                    Error::Unexpected(String::from("The bytes count overflowed on loading elf"))
                })?;
            }
        }
        if update_pc {
            self.update_pc(Self::REG::from_u64(e_entry));
            self.commit_pc();
        }
        Ok(bytes)
    }
    fn load_elf(&mut self, program: &Bytes, update_pc: bool) -> Result<u64, Error> {
        self.load_elf_inner(program, update_pc)
    }
    fn initialize_stack(
        &mut self,
        args: &[Bytes],
        stack_start: u64,
        stack_size: u64,
    ) -> Result<u64, Error> {
        if self.version() >= VERSION1 && args.is_empty() {
            let argc_size = u64::from(Self::REG::BITS / 8);
            let origin_sp = stack_start + stack_size;
            let unaligned_sp_address = origin_sp - argc_size;
            let aligned_sp_address = unaligned_sp_address & (!15);
            let used_bytes = origin_sp - aligned_sp_address;
            self.set_register(SP, Self::REG::from_u64(aligned_sp_address));
            return Ok(used_bytes);
        }
        self.set_register(SP, Self::REG::from_u64(stack_start + stack_size));
        let mut values = vec![Self::REG::from_u64(args.len() as u64)];
        for arg in args {
            let len = Self::REG::from_u64(arg.len() as u64 + 1);
            let address = self.registers()[SP].overflowing_sub(&len);
            self.memory_mut().store_bytes(address.to_u64(), arg)?;
            self.memory_mut()
                .store_byte(address.to_u64() + arg.len() as u64, 1, 0)?;
            values.push(address.clone());
            self.set_register(SP, address);
        }
        if self.version() >= VERSION1 {
            values.push(Self::REG::zero());
            let values_bytes =
                Self::REG::from_u64(Self::REG::BITS as u64 / 8 * values.len() as u64);
            let unaligned_sp_address = self.registers()[SP].overflowing_sub(&values_bytes).to_u64();
            let aligned_sp_address = unaligned_sp_address & (!15);
            let aligned_bytes = unaligned_sp_address - aligned_sp_address;
            self.set_register(
                SP,
                self.registers()[SP].overflowing_sub(&Self::REG::from_u64(aligned_bytes)),
            );
        }
        for value in values.iter().rev() {
            let address =
                self.registers()[SP].overflowing_sub(&Self::REG::from_u8(Self::REG::BITS / 8));
            if self.version() >= VERSION1 {
                if Self::REG::BITS == 64 {
                    self.memory_mut().store64(&address, value)?;
                } else {
                    self.memory_mut().store32(&address, value)?;
                }
            } else {
                self.memory_mut().store32(&address, value)?;
            }
            self.set_register(SP, address);
        }
        if self.registers()[SP].to_u64() < stack_start {
            return Err(Error::MemOutOfStack);
        }
        Ok(stack_start + stack_size - self.registers()[SP].to_u64())
    }
    #[cfg(feature = "pprof")]
    fn code(&self) -> &Bytes;
}
#[derive(Default)]
pub struct DefaultCoreMachine<R, M> {
    registers: [R; RISCV_GENERAL_REGISTER_NUMBER],
    pc: R,
    next_pc: R,
    reset_signal: bool,
    memory: M,
    cycles: u64,
    max_cycles: u64,
    running: bool,
    isa: u8,
    version: u32,
    #[cfg(feature = "pprof")]
    code: Bytes,
}
impl<R: Register, M: Memory<REG = R>> CoreMachine for DefaultCoreMachine<R, M> {
    type REG = R;
    type MEM = M;
    fn pc(&self) -> &Self::REG {
        &self.pc
    }
    fn update_pc(&mut self, pc: Self::REG) {
        self.next_pc = pc;
    }
    fn commit_pc(&mut self) {
        self.pc = self.next_pc.clone();
    }
    fn memory(&self) -> &Self::MEM {
        &self.memory
    }
    fn memory_mut(&mut self) -> &mut Self::MEM {
        &mut self.memory
    }
    fn registers(&self) -> &[Self::REG] {
        &self.registers
    }
    fn set_register(&mut self, idx: usize, value: Self::REG) {
        self.registers[idx] = value;
    }
    fn isa(&self) -> u8 {
        self.isa
    }
    fn version(&self) -> u32 {
        self.version
    }
}
impl<R: Register, M: Memory<REG = R>> SupportMachine for DefaultCoreMachine<R, M> {
    fn cycles(&self) -> u64 {
        self.cycles
    }
    fn set_cycles(&mut self, cycles: u64) {
        self.cycles = cycles;
    }
    fn max_cycles(&self) -> u64 {
        self.max_cycles
    }
    fn reset(&mut self, max_cycles: u64) {
        self.registers = Default::default();
        self.pc = Default::default();
        self.memory = M::new_with_memory(self.memory().memory_size());
        self.cycles = 0;
        self.max_cycles = max_cycles;
        self.reset_signal = true;
        self.memory_mut().set_lr(&R::from_u64(u64::MAX));
    }
    fn reset_signal(&mut self) -> bool {
        let ret = self.reset_signal;
        self.reset_signal = false;
        ret
    }
    fn running(&self) -> bool {
        self.running
    }
    fn set_running(&mut self, running: bool) {
        self.running = running;
    }
    fn load_elf(&mut self, program: &Bytes, update_pc: bool) -> Result<u64, Error> {
        #[cfg(feature = "pprof")]
        {
            self.code = program.clone();
        }
        self.load_elf_inner(program, update_pc)
    }
    #[cfg(feature = "pprof")]
    fn code(&self) -> &Bytes {
        &self.code
    }
}
impl<R: Register, M: Memory> DefaultCoreMachine<R, M> {
    pub fn new(isa: u8, version: u32, max_cycles: u64) -> Self {
        Self::new_with_memory(isa, version, max_cycles, RISCV_MAX_MEMORY)
    }
    pub fn new_with_memory(isa: u8, version: u32, max_cycles: u64, memory_size: usize) -> Self {
        Self {
            registers: Default::default(),
            pc: Default::default(),
            next_pc: Default::default(),
            reset_signal: Default::default(),
            memory: M::new_with_memory(memory_size),
            cycles: Default::default(),
            max_cycles,
            running: Default::default(),
            isa,
            version,
            #[cfg(feature = "pprof")]
            code: Default::default(),
        }
    }
    pub fn set_max_cycles(&mut self, cycles: u64) {
        self.max_cycles = cycles;
    }
    pub fn take_memory(self) -> M {
        self.memory
    }
}
pub type InstructionCycleFunc = dyn Fn(Instruction) -> u64 + Send + Sync;
pub struct DefaultMachine<Inner> {
    inner: Inner,
    pause: Pause,
    instruction_cycle_func: Box<InstructionCycleFunc>,
    debugger: Option<Box<dyn Debugger<Inner>>>,
    syscalls: Vec<Box<dyn Syscalls<Inner>>>,
    exit_code: i8,
}
impl<Inner: CoreMachine> CoreMachine for DefaultMachine<Inner> {
    type REG = <Inner as CoreMachine>::REG;
    type MEM = <Inner as CoreMachine>::MEM;
    fn pc(&self) -> &Self::REG {
        self.inner.pc()
    }
    fn update_pc(&mut self, pc: Self::REG) {
        self.inner.update_pc(pc);
    }
    fn commit_pc(&mut self) {
        self.inner.commit_pc();
    }
    fn memory(&self) -> &Self::MEM {
        self.inner.memory()
    }
    fn memory_mut(&mut self) -> &mut Self::MEM {
        self.inner.memory_mut()
    }
    fn registers(&self) -> &[Self::REG] {
        self.inner.registers()
    }
    fn set_register(&mut self, idx: usize, value: Self::REG) {
        self.inner.set_register(idx, value)
    }
    fn isa(&self) -> u8 {
        self.inner.isa()
    }
    fn version(&self) -> u32 {
        self.inner.version()
    }
}
impl<Inner: SupportMachine> SupportMachine for DefaultMachine<Inner> {
    fn cycles(&self) -> u64 {
        self.inner.cycles()
    }
    fn set_cycles(&mut self, cycles: u64) {
        self.inner.set_cycles(cycles)
    }
    fn max_cycles(&self) -> u64 {
        self.inner.max_cycles()
    }
    fn reset(&mut self, max_cycles: u64) {
        self.inner_mut().reset(max_cycles);
    }
    fn reset_signal(&mut self) -> bool {
        self.inner_mut().reset_signal()
    }
    fn running(&self) -> bool {
        self.inner.running()
    }
    fn set_running(&mut self, running: bool) {
        self.inner.set_running(running);
    }
    #[cfg(feature = "pprof")]
    fn code(&self) -> &Bytes {
        self.inner.code()
    }
}
impl<Inner: SupportMachine> Machine for DefaultMachine<Inner> {
    fn ecall(&mut self) -> Result<(), Error> {
        let code = self.registers()[A7].to_u64();
        match code {
            93 => {
                self.exit_code = self.registers()[A0].to_i8();
                self.set_running(false);
                Ok(())
            }
            _ => {
                for syscall in &mut self.syscalls {
                    let processed = syscall.ecall(&mut self.inner)?;
                    if processed {
                        if self.cycles() > self.max_cycles() {
                            return Err(Error::CyclesExceeded);
                        }
                        return Ok(());
                    }
                }
                Err(Error::InvalidEcall(code))
            }
        }
    }
    fn ebreak(&mut self) -> Result<(), Error> {
        if let Some(debugger) = &mut self.debugger {
            debugger.ebreak(&mut self.inner)
        } else {
            Ok(())
        }
    }
}
impl<Inner: CoreMachine> Display for DefaultMachine<Inner> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        writeln!(f, "pc  : 0x{:16X}", self.pc().to_u64())?;
        for (i, name) in REGISTER_ABI_NAMES.iter().enumerate() {
            write!(f, "{:4}: 0x{:16X}", name, self.registers()[i].to_u64())?;
            if (i + 1) % 4 == 0 {
                writeln!(f)?;
            } else {
                write!(f, " ")?;
            }
        }
        Ok(())
    }
}
impl<Inner: SupportMachine> DefaultMachine<Inner> {
    pub fn load_program(&mut self, program: &Bytes, args: &[Bytes]) -> Result<u64, Error> {
        let elf_bytes = self.load_elf(program, true)?;
        for syscall in &mut self.syscalls {
            syscall.initialize(&mut self.inner)?;
        }
        if let Some(debugger) = &mut self.debugger {
            debugger.initialize(&mut self.inner)?;
        }
        let memory_size = self.memory().memory_size();
        let stack_size = memory_size / 4;
        let stack_bytes =
            self.initialize_stack(args, (memory_size - stack_size) as u64, stack_size as u64)?;
        if self.inner.version() >= VERSION1 {
            debug_assert!(self.registers()[SP].to_u64() % 16 == 0);
        }
        let bytes = elf_bytes.checked_add(stack_bytes).ok_or_else(|| {
            Error::Unexpected(String::from(
                "The bytes count overflowed on loading program",
            ))
        })?;
        Ok(bytes)
    }
    pub fn take_inner(self) -> Inner {
        self.inner
    }
    pub fn pause(&self) -> Pause {
        self.pause.clone()
    }
    pub fn exit_code(&self) -> i8 {
        self.exit_code
    }
    pub fn instruction_cycle_func(&self) -> &InstructionCycleFunc {
        &self.instruction_cycle_func
    }
    pub fn inner_mut(&mut self) -> &mut Inner {
        &mut self.inner
    }
    pub fn run(&mut self) -> Result<i8, Error> {
        if self.isa() & ISA_MOP != 0 && self.version() == VERSION0 {
            return Err(Error::InvalidVersion);
        }
        let mut decoder = build_decoder::<Inner::REG>(self.isa(), self.version());
        self.set_running(true);
        while self.running() {
            if self.pause.has_interrupted() {
                self.pause.free();
                return Err(Error::Pause);
            }
            if self.reset_signal() {
                decoder.reset_instructions_cache();
            }
            self.step(&mut decoder)?;
        }
        Ok(self.exit_code())
    }
    pub fn step(&mut self, decoder: &mut Decoder) -> Result<(), Error> {
        let instruction = {
            let pc = self.pc().to_u64();
            let memory = self.memory_mut();
            decoder.decode(memory, pc)?
        };
        let cycles = self.instruction_cycle_func()(instruction);
        self.add_cycles(cycles)?;
        execute(instruction, self)
    }
}
pub struct DefaultMachineBuilder<Inner> {
    inner: Inner,
    instruction_cycle_func: Box<InstructionCycleFunc>,
    debugger: Option<Box<dyn Debugger<Inner>>>,
    syscalls: Vec<Box<dyn Syscalls<Inner>>>,
}
impl<Inner> DefaultMachineBuilder<Inner> {
    pub fn new(inner: Inner) -> Self {
        Self {
            inner,
            instruction_cycle_func: Box::new(|_| 0),
            debugger: None,
            syscalls: vec![],
        }
    }
    pub fn instruction_cycle_func(
        mut self,
        instruction_cycle_func: Box<InstructionCycleFunc>,
    ) -> Self {
        self.instruction_cycle_func = instruction_cycle_func;
        self
    }
    pub fn syscall(mut self, syscall: Box<dyn Syscalls<Inner>>) -> Self {
        self.syscalls.push(syscall);
        self
    }
    pub fn debugger(mut self, debugger: Box<dyn Debugger<Inner>>) -> Self {
        self.debugger = Some(debugger);
        self
    }
    pub fn build(self) -> DefaultMachine<Inner> {
        DefaultMachine {
            inner: self.inner,
            pause: Pause::new(),
            instruction_cycle_func: self.instruction_cycle_func,
            debugger: self.debugger,
            syscalls: self.syscalls,
            exit_code: 0,
        }
    }
}
#[derive(Clone, Default)]
pub struct Pause {
    s: Arc<AtomicU8>,
}
impl Pause {
    pub fn new() -> Self {
        Self {
            s: Arc::new(AtomicU8::new(0)),
        }
    }
    pub fn interrupt(&self) {
        self.s.store(1, Ordering::SeqCst);
    }
    pub fn has_interrupted(&self) -> bool {
        self.s.load(Ordering::SeqCst) != 0
    }
    pub fn get_raw_ptr(&self) -> *mut u8 {
        &*self.s as *const _ as *mut u8
    }
    pub fn free(&mut self) {
        self.s.store(0, Ordering::SeqCst);
    }
}
#[cfg(test)]
mod tests {
    use std::sync::atomic::AtomicU8;
    #[test]
    fn test_atomicu8() {
        assert_eq!(std::mem::size_of::<AtomicU8>(), 1);
    }
}