<commit_before>use core::intrinsics;

// NOTE This function and the ones below are implemented using assembly because they using a custom
// calling convention which can't be implemented using a normal Rust function.
// NOTE The only difference between the iOS and non-iOS versions of those functions is that the iOS
// versions use 3 leading underscores in the names of called functions instead of 2.
#[cfg(not(any(target_os = "ios", target_env = "msvc")))]
#[naked]
#[cfg_attr(not(feature = "mangled-names"), no_mangle)]
pub unsafe fn __aeabi_uidivmod() {
    asm!("push {lr}
          sub sp, sp, #4
          mov r2, sp
          bl __udivmodsi4
          ldr r1, [sp]
          add sp, sp, #4
          pop {pc}" ::: "memory" : "volatile");
    intrinsics::unreachable();
}

#[cfg(target_os = "ios")]
#[naked]
#[cfg_attr(not(feature = "mangled-names"), no_mangle)]
pub unsafe fn __aeabi_uidivmod() {
    asm!("push {lr}
          sub sp, sp, #4
          mov r2, sp
          bl ___udivmodsi4
          ldr r1, [sp]
          add sp, sp, #4
          pop {pc}" ::: "memory" : "volatile");
    intrinsics::unreachable();
}

#[cfg(not(target_os = "ios"))]
#[naked]
#[cfg_attr(not(feature = "mangled-names"), no_mangle)]
pub unsafe fn __aeabi_uldivmod() {
    asm!("push {r4, lr}
          sub sp, sp, #16
          add r4, sp, #8
          str r4, [sp]
          bl __udivmoddi4
          ldr r2, [sp, #8]
          ldr r3, [sp, #12]
          add sp, sp, #16
          pop {r4, pc}" ::: "memory" : "volatile");
    intrinsics::unreachable();
}

#[cfg(target_os = "ios")]
#[naked]
#[cfg_attr(not(feature = "mangled-names"), no_mangle)]
pub unsafe fn __aeabi_uldivmod() {
    asm!("push {r4, lr}
          sub sp, sp, #16
          add r4, sp, #8
          str r4, [sp]
          bl ___udivmoddi4
          ldr r2, [sp, #8]
          ldr r3, [sp, #12]
          add sp, sp, #16
          pop {r4, pc}" ::: "memory" : "volatile");
    intrinsics::unreachable();
}

#[cfg(not(target_os = "ios"))]
#[naked]
#[cfg_attr(not(feature = "mangled-names"), no_mangle)]
pub unsafe fn __aeabi_idivmod() {
    asm!("push {r0, r1, r4, lr}
          bl __aeabi_idiv
          pop {r1, r2}
          muls r2, r2, r0
          subs r1, r1, r2
          pop {r4, pc}" ::: "memory" : "volatile");
    intrinsics::unreachable();
}

#[cfg(target_os = "ios")]
#[naked]
#[cfg_attr(not(feature = "mangled-names"), no_mangle)]
pub unsafe fn __aeabi_idivmod() {
    asm!("push {r0, r1, r4, lr}
          bl ___aeabi_idiv
          pop {r1, r2}
          muls r2, r2, r0
          subs r1, r1, r2
          pop {r4, pc}" ::: "memory" : "volatile");
    intrinsics::unreachable();
}

#[cfg(not(target_os = "ios"))]
#[naked]
#[cfg_attr(not(feature = "mangled-names"), no_mangle)]
pub unsafe fn __aeabi_ldivmod() {
    asm!("push {r4, lr}
          sub sp, sp, #16
          add r4, sp, #8
          str r4, [sp]
          bl __divmoddi4
          ldr r2, [sp, #8]
          ldr r3, [sp, #12]
          add sp, sp, #16
          pop {r4, pc}" ::: "memory" : "volatile");
    intrinsics::unreachable();
}

#[cfg(target_os = "ios")]
#[naked]
#[cfg_attr(not(feature = "mangled-names"), no_mangle)]
pub unsafe fn __aeabi_ldivmod() {
    asm!("push {r4, lr}
          sub sp, sp, #16
          add r4, sp, #8
          str r4, [sp]
          bl ___divmoddi4
          ldr r2, [sp, #8]
          ldr r3, [sp, #12]
          add sp, sp, #16
          pop {r4, pc}" ::: "memory" : "volatile");
    intrinsics::unreachable();
}

// FIXME: The `*4` and `*8` variants should be defined as aliases.

#[cfg(not(target_os = "ios"))]
#[cfg_attr(not(feature = "mangled-names"), no_mangle)]
#[cfg_attr(thumb, linkage = "weak")]
pub unsafe extern "aapcs" fn __aeabi_memcpy(dest: *mut u8, src: *const u8, n: usize) {
    ::mem::memcpy(dest, src, n);
}

#[cfg(not(target_os = "ios"))]
#[cfg_attr(not(feature = "mangled-names"), no_mangle)]
#[cfg_attr(thumb, linkage = "weak")]
pub unsafe extern "aapcs" fn __aeabi_memcpy4(dest: *mut u8, src: *const u8, mut n: usize) {
    use core::ptr;

    let mut dest = dest as *mut u32;
    let mut src = src as *mut u32;

    while n >= 4 {
        ptr::write(dest, ptr::read(src));
        dest = dest.offset(1);
        src = src.offset(1);
        n -= 4;
    }

    __aeabi_memcpy(dest as *mut u8, src as *const u8, n);
}

#[cfg(not(target_os = "ios"))]
#[cfg_attr(not(feature = "mangled-names"), no_mangle)]
#[cfg_attr(thumb, linkage = "weak")]
pub unsafe extern "aapcs" fn __aeabi_memcpy8(dest: *mut u8, src: *const u8, n: usize) {
    __aeabi_memcpy4(dest, src, n);
}

#[cfg(not(target_os = "ios"))]
#[cfg_attr(not(feature = "mangled-names"), no_mangle)]
#[cfg_attr(thumb, linkage = "weak")]
pub unsafe extern "aapcs" fn __aeabi_memmove(dest: *mut u8, src: *const u8, n: usize) {
    ::mem::memmove(dest, src, n);
}

#[cfg(not(target_os = "ios"))]
#[cfg_attr(not(feature = "mangled-names"), no_mangle)]
#[cfg_attr(thumb, linkage = "weak")]
pub unsafe extern "aapcs" fn __aeabi_memmove4(dest: *mut u8, src: *const u8, n: usize) {
    __aeabi_memmove(dest, src, n);
}

#[cfg(not(target_os = "ios"))]
#[cfg_attr(not(feature = "mangled-names"), no_mangle)]
#[cfg_attr(thumb, linkage = "weak")]
pub unsafe extern "aapcs" fn __aeabi_memmove8(dest: *mut u8, src: *const u8, n: usize) {
    __aeabi_memmove(dest, src, n);
}

#[cfg(not(target_os = "ios"))]
#[cfg_attr(not(feature = "mangled-names"), no_mangle)]
#[cfg_attr(thumb, linkage = "weak")]
pub unsafe extern "aapcs" fn __aeabi_memset(dest: *mut u8, n: usize, c: i32) {
    // Note the different argument order
    ::mem::memset(dest, c, n);
}

#[cfg(not(target_os = "ios"))]
#[cfg_attr(not(feature = "mangled-names"), no_mangle)]
#[cfg_attr(thumb, linkage = "weak")]
pub unsafe extern "aapcs" fn __aeabi_memset4(dest: *mut u8, mut n: usize, c: i32) {
    use core::ptr;

    let mut dest = dest as *mut u32;

    let byte = (c as u32) & 0xff;
    let c = (byte << 24) | (byte << 16) | (byte << 8) | byte;

    while n >= 4 {
        ptr::write(dest, c);
        dest = dest.offset(1);
        n -= 4;
    }

    __aeabi_memset(dest as *mut u8, n, byte as i32);
}

#[cfg(not(target_os = "ios"))]
#[cfg_attr(not(feature = "mangled-names"), no_mangle)]
#[cfg_attr(thumb, linkage = "weak")]
pub unsafe extern "aapcs" fn __aeabi_memset8(dest: *mut u8, n: usize, c: i32) {
    __aeabi_memset4(dest, n, c);
}

#[cfg(not(target_os = "ios"))]
#[cfg_attr(not(feature = "mangled-names"), no_mangle)]
#[cfg_attr(thumb, linkage = "weak")]
pub unsafe extern "aapcs" fn __aeabi_memclr(dest: *mut u8, n: usize) {
    __aeabi_memset(dest, n, 0);
}

#[cfg(not(target_os = "ios"))]
#[cfg_attr(not(feature = "mangled-names"), no_mangle)]
#[cfg_attr(thumb, linkage = "weak")]
pub unsafe extern "aapcs" fn __aeabi_memclr4(dest: *mut u8, n: usize) {
    __aeabi_memset4(dest, n, 0);
}

#[cfg(not(target_os = "ios"))]
#[cfg_attr(not(feature = "mangled-names"), no_mangle)]
#[cfg_attr(thumb, linkage = "weak")]
pub unsafe extern "aapcs" fn __aeabi_memclr8(dest: *mut u8, n: usize) {
    __aeabi_memset4(dest, n, 0);
}
<commit_msg>start of __clzsi2<commit_after>use core::intrinsics;

// NOTE This function and the ones below are implemented using assembly because they using a custom
// calling convention which can't be implemented using a normal Rust function.
// NOTE The only difference between the iOS and non-iOS versions of those functions is that the iOS
// versions use 3 leading underscores in the names of called functions instead of 2.
#[cfg(not(any(target_os = "ios", target_env = "msvc")))]
#[naked]
#[cfg_attr(not(feature = "mangled-names"), no_mangle)]
pub unsafe fn __aeabi_uidivmod() {
    asm!("push {lr}
          sub sp, sp, #4
          mov r2, sp
          bl __udivmodsi4
          ldr r1, [sp]
          add sp, sp, #4
          pop {pc}" ::: "memory" : "volatile");
    intrinsics::unreachable();
}

#[cfg(target_os = "ios")]
#[naked]
#[cfg_attr(not(feature = "mangled-names"), no_mangle)]
pub unsafe fn __aeabi_uidivmod() {
    asm!("push {lr}
          sub sp, sp, #4
          mov r2, sp
          bl ___udivmodsi4
          ldr r1, [sp]
          add sp, sp, #4
          pop {pc}" ::: "memory" : "volatile");
    intrinsics::unreachable();
}

#[cfg(not(target_os = "ios"))]
#[naked]
#[cfg_attr(not(feature = "mangled-names"), no_mangle)]
pub unsafe fn __aeabi_uldivmod() {
    asm!("push {r4, lr}
          sub sp, sp, #16
          add r4, sp, #8
          str r4, [sp]
          bl __udivmoddi4
          ldr r2, [sp, #8]
          ldr r3, [sp, #12]
          add sp, sp, #16
          pop {r4, pc}" ::: "memory" : "volatile");
    intrinsics::unreachable();
}

#[cfg(target_os = "ios")]
#[naked]
#[cfg_attr(not(feature = "mangled-names"), no_mangle)]
pub unsafe fn __aeabi_uldivmod() {
    asm!("push {r4, lr}
          sub sp, sp, #16
          add r4, sp, #8
          str r4, [sp]
          bl ___udivmoddi4
          ldr r2, [sp, #8]
          ldr r3, [sp, #12]
          add sp, sp, #16
          pop {r4, pc}" ::: "memory" : "volatile");
    intrinsics::unreachable();
}

#[cfg(not(target_os = "ios"))]
#[naked]
#[cfg_attr(not(feature = "mangled-names"), no_mangle)]
pub unsafe fn __aeabi_idivmod() {
    asm!("push {r0, r1, r4, lr}
          bl __aeabi_idiv
          pop {r1, r2}
          muls r2, r2, r0
          subs r1, r1, r2
          pop {r4, pc}" ::: "memory" : "volatile");
    intrinsics::unreachable();
}

#[cfg(target_os = "ios")]
#[naked]
#[cfg_attr(not(feature = "mangled-names"), no_mangle)]
pub unsafe fn __aeabi_idivmod() {
    asm!("push {r0, r1, r4, lr}
          bl ___aeabi_idiv
          pop {r1, r2}
          muls r2, r2, r0
          subs r1, r1, r2
          pop {r4, pc}" ::: "memory" : "volatile");
    intrinsics::unreachable();
}

#[cfg(not(target_os = "ios"))]
#[naked]
#[cfg_attr(not(feature = "mangled-names"), no_mangle)]
pub unsafe fn __aeabi_ldivmod() {
    asm!("push {r4, lr}
          sub sp, sp, #16
          add r4, sp, #8
          str r4, [sp]
          bl __divmoddi4
          ldr r2, [sp, #8]
          ldr r3, [sp, #12]
          add sp, sp, #16
          pop {r4, pc}" ::: "memory" : "volatile");
    intrinsics::unreachable();
}

#[cfg(target_os = "ios")]
#[naked]
#[cfg_attr(not(feature = "mangled-names"), no_mangle)]
pub unsafe fn __aeabi_ldivmod() {
    asm!("push {r4, lr}
          sub sp, sp, #16
          add r4, sp, #8
          str r4, [sp]
          bl ___divmoddi4
          ldr r2, [sp, #8]
          ldr r3, [sp, #12]
          add sp, sp, #16
          pop {r4, pc}" ::: "memory" : "volatile");
    intrinsics::unreachable();
}

// FIXME: The `*4` and `*8` variants should be defined as aliases.

#[cfg(not(target_os = "ios"))]
#[cfg_attr(not(feature = "mangled-names"), no_mangle)]
#[cfg_attr(thumb, linkage = "weak")]
pub unsafe extern "aapcs" fn __aeabi_memcpy(dest: *mut u8, src: *const u8, n: usize) {
    ::mem::memcpy(dest, src, n);
}

#[cfg(not(target_os = "ios"))]
#[cfg_attr(not(feature = "mangled-names"), no_mangle)]
#[cfg_attr(thumb, linkage = "weak")]
pub unsafe extern "aapcs" fn __aeabi_memcpy4(dest: *mut u8, src: *const u8, mut n: usize) {
    use core::ptr;

    let mut dest = dest as *mut u32;
    let mut src = src as *mut u32;

    while n >= 4 {
        ptr::write(dest, ptr::read(src));
        dest = dest.offset(1);
        src = src.offset(1);
        n -= 4;
    }

    __aeabi_memcpy(dest as *mut u8, src as *const u8, n);
}

#[cfg(not(target_os = "ios"))]
#[cfg_attr(not(feature = "mangled-names"), no_mangle)]
#[cfg_attr(thumb, linkage = "weak")]
pub unsafe extern "aapcs" fn __aeabi_memcpy8(dest: *mut u8, src: *const u8, n: usize) {
    __aeabi_memcpy4(dest, src, n);
}

#[cfg(not(target_os = "ios"))]
#[cfg_attr(not(feature = "mangled-names"), no_mangle)]
#[cfg_attr(thumb, linkage = "weak")]
pub unsafe extern "aapcs" fn __aeabi_memmove(dest: *mut u8, src: *const u8, n: usize) {
    ::mem::memmove(dest, src, n);
}

#[cfg(not(target_os = "ios"))]
#[cfg_attr(not(feature = "mangled-names"), no_mangle)]
#[cfg_attr(thumb, linkage = "weak")]
pub unsafe extern "aapcs" fn __aeabi_memmove4(dest: *mut u8, src: *const u8, n: usize) {
    __aeabi_memmove(dest, src, n);
}

#[cfg(not(target_os = "ios"))]
#[cfg_attr(not(feature = "mangled-names"), no_mangle)]
#[cfg_attr(thumb, linkage = "weak")]
pub unsafe extern "aapcs" fn __aeabi_memmove8(dest: *mut u8, src: *const u8, n: usize) {
    __aeabi_memmove(dest, src, n);
}

#[cfg(not(target_os = "ios"))]
#[cfg_attr(not(feature = "mangled-names"), no_mangle)]
#[cfg_attr(thumb, linkage = "weak")]
pub unsafe extern "aapcs" fn __aeabi_memset(dest: *mut u8, n: usize, c: i32) {
    // Note the different argument order
    ::mem::memset(dest, c, n);
}

#[cfg(not(target_os = "ios"))]
#[cfg_attr(not(feature = "mangled-names"), no_mangle)]
#[cfg_attr(thumb, linkage = "weak")]
pub unsafe extern "aapcs" fn __aeabi_memset4(dest: *mut u8, mut n: usize, c: i32) {
    use core::ptr;

    let mut dest = dest as *mut u32;

    let byte = (c as u32) & 0xff;
    let c = (byte << 24) | (byte << 16) | (byte << 8) | byte;

    while n >= 4 {
        ptr::write(dest, c);
        dest = dest.offset(1);
        n -= 4;
    }

    __aeabi_memset(dest as *mut u8, n, byte as i32);
}

#[cfg(not(target_os = "ios"))]
#[cfg_attr(not(feature = "mangled-names"), no_mangle)]
#[cfg_attr(thumb, linkage = "weak")]
pub unsafe extern "aapcs" fn __aeabi_memset8(dest: *mut u8, n: usize, c: i32) {
    __aeabi_memset4(dest, n, c);
}

#[cfg(not(target_os = "ios"))]
#[cfg_attr(not(feature = "mangled-names"), no_mangle)]
#[cfg_attr(thumb, linkage = "weak")]
pub unsafe extern "aapcs" fn __aeabi_memclr(dest: *mut u8, n: usize) {
    __aeabi_memset(dest, n, 0);
}

#[cfg(not(target_os = "ios"))]
#[cfg_attr(not(feature = "mangled-names"), no_mangle)]
#[cfg_attr(thumb, linkage = "weak")]
pub unsafe extern "aapcs" fn __aeabi_memclr4(dest: *mut u8, n: usize) {
    __aeabi_memset4(dest, n, 0);
}

#[cfg(not(target_os = "ios"))]
#[cfg_attr(not(feature = "mangled-names"), no_mangle)]
#[cfg_attr(thumb, linkage = "weak")]
pub unsafe extern "aapcs" fn __aeabi_memclr8(dest: *mut u8, n: usize) {
    __aeabi_memset4(dest, n, 0);
}

#[no_mangle]
#[cfg(any(target_pointer_width = "16", target_pointer_width = "32", target_pointer_width = "64"))]
pub extern "C" fn __clzsi2(mut x: usize) -> usize {
  // TODO: const this? Requires const if
  let mut y: usize;
  let mut n: usize = {
    #[cfg(target_pointer_width = "64")]
    {
      64
    }
    #[cfg(target_pointer_width = "32")]
    {
      32
    }
    #[cfg(target_pointer_width = "16")]
    {
      16
    }
  };
  #[cfg(target_pointer_width = "64")]
  {
    y = x >> 32;
    if y != 0 {
      n -= 32;
      x = y;
    }
  }
  #[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))]
  {
    y = x >> 16;
    if y != 0 {
      n -= 16;
      x = y;
    }
  }
  y = x >> 8;
  if y != 0 {
    n -= 8;
    x = y;
  }
  y = x >> 4;
  if y != 0 {
    n -= 4;
    x = y;
  }
  y = x >> 2;
  if y != 0 {
    n -= 2;
    x = y;
  }
  y = x >> 1;
  if y != 0 {
    n - 2
  } else {
    n - x
  }
}
<|endoftext|>


<commit_before>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

#![forbid(unsafe_code)]

//! Used to perform catching up between nodes for committed states.
//! Used for node restarts, network partitions, full node syncs
#![recursion_limit = "1024"]

use executor_types::ExecutedTrees;
use libra_types::{
    account_address::AccountAddress, epoch_state::EpochState,
    ledger_info::LedgerInfoWithSignatures, validator_verifier::ValidatorVerifier,
};
pub use synchronizer::{StateSyncClient, StateSynchronizer};

mod chunk_request;
mod chunk_response;
mod coordinator;
mod counters;
mod executor_proxy;
pub mod network;
mod peer_manager;
mod synchronizer;

type PeerId = AccountAddress;

/// The state distinguishes between the following fields:
/// * highest_local_li is keeping the latest certified ledger info
/// * synced_trees is keeping the latest state in the transaction accumulator and state tree.
///
/// While `highest_local_li` can be used for helping the others (corresponding to the highest
/// version we have a proof for), `synced_trees` is used for retrieving missing chunks
/// for the local storage.
#[derive(Clone)]
pub struct SynchronizerState {
    pub highest_local_li: LedgerInfoWithSignatures,
    pub synced_trees: ExecutedTrees,
    // Corresponds to the current epoch if the highest local LI is in the middle of the epoch,
    // or the next epoch if the highest local LI is the final LI in the current epoch.
    pub trusted_epoch: EpochState,
}

impl SynchronizerState {
    pub fn new(
        highest_local_li: LedgerInfoWithSignatures,
        synced_trees: ExecutedTrees,
        current_epoch_state: EpochState,
    ) -> Self {
        let trusted_epoch = highest_local_li
            .ledger_info()
            .next_epoch_state()
            .cloned()
            .unwrap_or(current_epoch_state);
        SynchronizerState {
            highest_local_li,
            synced_trees,
            trusted_epoch,
        }
    }

    /// The highest available version in the local storage (even if it's not covered by the LI).
    pub fn highest_version_in_local_storage(&self) -> u64 {
        self.synced_trees.version().unwrap_or(0)
    }

    pub fn epoch(&self) -> u64 {
        self.trusted_epoch.epoch
    }

    pub fn verifier(&self) -> &ValidatorVerifier {
        &self.trusted_epoch.verifier
    }
}

#[cfg(test)]
mod tests;
<commit_msg>Removing verifier from state-synchronizer/src/lib.rs<commit_after>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

#![forbid(unsafe_code)]

//! Used to perform catching up between nodes for committed states.
//! Used for node restarts, network partitions, full node syncs
#![recursion_limit = "1024"]

use executor_types::ExecutedTrees;
use libra_types::{
    account_address::AccountAddress, epoch_state::EpochState, ledger_info::LedgerInfoWithSignatures,
};
pub use synchronizer::{StateSyncClient, StateSynchronizer};

mod chunk_request;
mod chunk_response;
mod coordinator;
mod counters;
mod executor_proxy;
pub mod network;
mod peer_manager;
mod synchronizer;

type PeerId = AccountAddress;

/// The state distinguishes between the following fields:
/// * highest_local_li is keeping the latest certified ledger info
/// * synced_trees is keeping the latest state in the transaction accumulator and state tree.
///
/// While `highest_local_li` can be used for helping the others (corresponding to the highest
/// version we have a proof for), `synced_trees` is used for retrieving missing chunks
/// for the local storage.
#[derive(Clone)]
pub struct SynchronizerState {
    pub highest_local_li: LedgerInfoWithSignatures,
    pub synced_trees: ExecutedTrees,
    // Corresponds to the current epoch if the highest local LI is in the middle of the epoch,
    // or the next epoch if the highest local LI is the final LI in the current epoch.
    pub trusted_epoch: EpochState,
}

impl SynchronizerState {
    pub fn new(
        highest_local_li: LedgerInfoWithSignatures,
        synced_trees: ExecutedTrees,
        current_epoch_state: EpochState,
    ) -> Self {
        let trusted_epoch = highest_local_li
            .ledger_info()
            .next_epoch_state()
            .cloned()
            .unwrap_or(current_epoch_state);
        SynchronizerState {
            highest_local_li,
            synced_trees,
            trusted_epoch,
        }
    }

    /// The highest available version in the local storage (even if it's not covered by the LI).
    pub fn highest_version_in_local_storage(&self) -> u64 {
        self.synced_trees.version().unwrap_or(0)
    }

    pub fn epoch(&self) -> u64 {
        self.trusted_epoch.epoch
    }
}

#[cfg(test)]
mod tests;
<|endoftext|>


<commit_before>use super::interconnect::Interconnect;
use super::interconnect::END_RESERVED;

const INSTRUCTION_SIZE: u16 = 2;

#[derive(Default, Debug)]
pub struct Cpu {
    // Interconnect is used to control system resources like rom and memory.
    interconnect: Interconnect,

    // Program counter.
    pc: u16,

    // The function call stack.
    stack: [u16; 16],

    // Stack pointer.
    sp: u8,

    // General purpose registers v0-vf.
    v0: u8,
    v1: u8,
    v2: u8,
    v3: u8,
    v4: u8,
    v5: u8,
    v6: u8,
    v7: u8,
    v8: u8,
    v9: u8,
    va: u8,
    vb: u8,
    vc: u8,
    vd: u8,
    ve: u8,
    vf: u8,

    // Address register "I".
    i: u16,

    // Timer and sound registers.
    dt: u8,
    st: u8,
}

impl Cpu {
    pub fn new(interconnect: Interconnect) -> Cpu {
        Cpu {
            interconnect: interconnect,
            pc: END_RESERVED as u16,
            ..Cpu::default()
        }
    }

    /// Execute instructions from ram.
    pub fn run(&mut self) {
        loop {
            let word = self.interconnect.read_word(self.pc);

            // Execute until the subroutine ends.
            if self.execute_instruction(word) {
                break
            }
        }
    }

    #[inline(always)]
    fn execute_instruction(&mut self, instr: u16) -> bool {
        let opcode = (instr >> 12) as u8;

        //println!("{:#x}", instr);

        match opcode {
            0x6 => {
                // 6XNN - LD VX, NN
                //
                // Sets VX to NN.

                let regx = ((instr << 4) >> 12) as u8;
                let byte = ((instr << 8) >> 8) as u8;
                self.set_reg(regx, byte);
            },
            0xa => {
                // ANNN - LD I, NNN
                //
                // Sets I to the address NNN.

                let addr = ((instr << 4) >> 4) as u16;
                self.i = addr;
            },
            0xd => {
                // DXYN - DRW VX, VY, N
                //
                // Sprites stored in memory at location in index register (I),
                // 8bits wide. Wraps around the screen. If when drawn, clears a
                // pixel, register VF is set to 1 otherwise it is zero.
                //
                // All drawing is XOR drawing (i.e. it toggles the screen
                // pixels). Sprites are drawn starting at position VX, VY. N is
                // the number of 8bit rows that need to be drawn. If N is
                // greater than 1, second line continues at position VX, VY+1,
                // and so on.

                let regx = ((instr << 4) >> 12) as u8;
                let regy = ((instr << 8) >> 12) as u8;
                let nibble = ((instr << 12) >> 12) as usize;

                // Read N (nibble) bytes out out of memory starting at address
                // register I into our sprite.
                let mut sprite = vec![0 as u8; nibble];
                for i in 0..nibble {
                    sprite[i] = self.interconnect.ram[self.i as usize + i];
                }

                // Get screen coordinates from the requested registers.
                let x = self.get_reg(regx);
                let y = self.get_reg(regy);

                // Draw the sprite and store collision detection results in vf.
                self.vf = self.interconnect.draw(x as usize, y as usize, sprite);
            },
            0x2 => {
                // 2NNN - CALL NNN
                //
                // Calls subroutine at NNN.

                let addr = ((instr << 4) >> 4) as u16;

                // Add the current program counter to the call stack.
                self.stack[self.sp as usize] = self.pc;
                self.sp += 1;

                // Set the program counter to the call address begin executing
                // the subroutine.
                self.pc = addr;
                self.run();

                panic!("unhandled");
            },
            0xf => {
                let regx = ((instr << 4) >> 12) as u8;
                let identifier = ((instr << 8) >> 8) as u8;

                match identifier {
                    0x33 => {
                        // FX33 - LD B, VX
                        //
                        // Stores the Binary-coded decimal representation of VX,
                        // with the most significant of three digits at the
                        // address in I, the middle digit at I plus 1, and the
                        // least significant digit at I plus 2. (In other words,
                        // take the decimal representation of VX, place the
                        // hundreds digit in memory at location in I, the tens
                        // digit at location I+1, and the ones digit at
                        // location I+2.)

                        const DECIMAL_LENGTH: usize = 3;

                        let mut x: u8 = self.get_reg(regx);
                        let mut digits = vec![0 as u8; DECIMAL_LENGTH];
                        let mut digit_count: usize = 0;

                        // Organize the digits in the decimal into a slice.
                        while x > 0 {
                            digit_count += 1;
                            digits[DECIMAL_LENGTH - digit_count] = x % 10;
                            x /= 10;
                        }

                        // Set I, I+1, and I+3 to the values of the digits.
                        let i: usize = self.i as usize;
                        self.interconnect.ram[i] = digits[0];
                        self.interconnect.ram[i + 1] = digits[1];
                        self.interconnect.ram[i + 2] = digits[2];
                    },
                    0x65 => {
                        // FX65 - LD VX, [I]
                        //
                        // Fills V0 to VX with values from memory starting at
                        // address I.

                        let i: usize = self.i as usize;
                        let end_reg = (regx + 1) as usize;

                        for register in 0x0..end_reg {
                            let mem = self.interconnect.ram[i + register];
                            self.set_reg(register as u8, mem);
                        }
                    },
                    0x29 => {
                        // FX29 - LD F, VX
                        //
                        // Sets I to the location of the sprite for the
                        // character in VX. Characters 0-F (in hexadecimal) are
                        // represented by a 4x5 font.

                        let x: u8 = self.get_reg(regx);
                        self.i = self.interconnect.get_font(x);
                    },
                    _ => {
                        println!("cpu: {:#?}", self);
                        panic!("Found unknown identifier at instruction: {:#x}, addr: {:#x}", instr, self.pc);
                    }
                }
            },
            _ => {
                println!("cpu: {:#?}", self);
                panic!("Found unknown opcode at instruction: {:#x}, addr: {:#x}", instr, self.pc);
            }
        }

        // Increment the program counter to the next instruction.
        self.pc += INSTRUCTION_SIZE;

        false
    }

    /// Gets the value at a specified register.
    fn get_reg(&mut self, reg: u8) -> u8 {
        match reg {
            0x0 => self.v0,
            0x1 => self.v1,
            0x2 => self.v2,
            0x3 => self.v3,
            0x4 => self.v4,
            0x5 => self.v5,
            0x6 => self.v6,
            0x7 => self.v7,
            0x8 => self.v8,
            0x9 => self.v9,
            0xa => self.va,
            0xb => self.vb,
            0xc => self.vc,
            0xd => self.vd,
            0xe => self.ve,
            0xf => self.vf,
            _ => {
                panic!("Cannot get unknown register: V{:X}", reg);
            }
        }
    }

    /// Sets the value of a general purpose register.
    fn set_reg(&mut self, reg: u8, byte: u8) {
        match reg {
            0x0 => self.v0 = byte,
            0x1 => self.v1 = byte,
            0x2 => self.v2 = byte,
            0x3 => self.v3 = byte,
            0x4 => self.v4 = byte,
            0x5 => self.v5 = byte,
            0x6 => self.v6 = byte,
            0x7 => self.v7 = byte,
            0x8 => self.v8 = byte,
            0x9 => self.v9 = byte,
            0xa => self.va = byte,
            0xb => self.vb = byte,
            0xc => self.vc = byte,
            0xd => self.vd = byte,
            0xe => self.ve = byte,
            0xf => self.vf = byte,
            _ => {
                panic!("Cannot set unknown register: V{:X}", reg);
            }
        }
    }
}
<commit_msg>Added 7XNN, ADD VX, NN<commit_after>use super::interconnect::Interconnect;
use super::interconnect::END_RESERVED;

const INSTRUCTION_SIZE: u16 = 2;

#[derive(Default, Debug)]
pub struct Cpu {
    // Interconnect is used to control system resources like rom and memory.
    interconnect: Interconnect,

    // Program counter.
    pc: u16,

    // The function call stack.
    stack: [u16; 16],

    // Stack pointer.
    sp: u8,

    // General purpose registers v0-vf.
    v0: u8,
    v1: u8,
    v2: u8,
    v3: u8,
    v4: u8,
    v5: u8,
    v6: u8,
    v7: u8,
    v8: u8,
    v9: u8,
    va: u8,
    vb: u8,
    vc: u8,
    vd: u8,
    ve: u8,
    vf: u8,

    // Address register "I".
    i: u16,

    // Timer and sound registers.
    dt: u8,
    st: u8,
}

impl Cpu {
    pub fn new(interconnect: Interconnect) -> Cpu {
        Cpu {
            interconnect: interconnect,
            pc: END_RESERVED as u16,
            ..Cpu::default()
        }
    }

    /// Execute instructions from ram.
    pub fn run(&mut self) {
        loop {
            let word = self.interconnect.read_word(self.pc);

            // Execute until the subroutine ends.
            if self.execute_instruction(word) {
                break
            }
        }
    }

    #[inline(always)]
    fn execute_instruction(&mut self, instr: u16) -> bool {
        let opcode = (instr >> 12) as u8;

        //println!("{:#x}", instr);

        match opcode {
            0x2 => {
                // 2NNN - CALL NNN
                //
                // Calls subroutine at NNN.

                let addr = ((instr << 4) >> 4) as u16;

                // Add the current program counter to the call stack.
                self.stack[self.sp as usize] = self.pc;
                self.sp += 1;

                // Set the program counter to the call address begin executing
                // the subroutine.
                self.pc = addr;
                self.run();

                panic!("unhandled");
            },
            0x6 => {
                // 6XNN - LD VX, NN
                //
                // Sets VX to NN.

                let regx = ((instr << 4) >> 12) as u8;
                let byte = ((instr << 8) >> 8) as u8;
                self.set_reg(regx, byte);
            },
            0x7 => {
                // 7XNN - ADD VX, NN
                //
                // Adds NN to VX.

                let regx = ((instr << 4) >> 12) as u8;
                let byte = ((instr << 8) >> 8) as u8;

                let result = self.get_reg(regx) + byte;
                self.set_reg(regx, result);
            },
            0xa => {
                // ANNN - LD I, NNN
                //
                // Sets I to the address NNN.

                let addr = ((instr << 4) >> 4) as u16;
                self.i = addr;
            },
            0xd => {
                // DXYN - DRW VX, VY, N
                //
                // Sprites stored in memory at location in index register (I),
                // 8bits wide. Wraps around the screen. If when drawn, clears a
                // pixel, register VF is set to 1 otherwise it is zero.
                //
                // All drawing is XOR drawing (i.e. it toggles the screen
                // pixels). Sprites are drawn starting at position VX, VY. N is
                // the number of 8bit rows that need to be drawn. If N is
                // greater than 1, second line continues at position VX, VY+1,
                // and so on.

                let regx = ((instr << 4) >> 12) as u8;
                let regy = ((instr << 8) >> 12) as u8;
                let nibble = ((instr << 12) >> 12) as usize;

                // Read N (nibble) bytes out out of memory starting at address
                // register I into our sprite.
                let mut sprite = vec![0 as u8; nibble];
                for i in 0..nibble {
                    sprite[i] = self.interconnect.ram[self.i as usize + i];
                }

                // Get screen coordinates from the requested registers.
                let x = self.get_reg(regx);
                let y = self.get_reg(regy);

                // Draw the sprite and store collision detection results in vf.
                self.vf = self.interconnect.draw(x as usize, y as usize, sprite);
            },
            0xf => {
                let regx = ((instr << 4) >> 12) as u8;
                let identifier = ((instr << 8) >> 8) as u8;

                match identifier {
                    0x29 => {
                        // FX29 - LD F, VX
                        //
                        // Sets I to the location of the sprite for the
                        // character in VX. Characters 0-F (in hexadecimal) are
                        // represented by a 4x5 font.

                        let x: u8 = self.get_reg(regx);
                        self.i = self.interconnect.get_font(x);
                    },
                    0x33 => {
                        // FX33 - LD B, VX
                        //
                        // Stores the Binary-coded decimal representation of VX,
                        // with the most significant of three digits at the
                        // address in I, the middle digit at I plus 1, and the
                        // least significant digit at I plus 2. (In other words,
                        // take the decimal representation of VX, place the
                        // hundreds digit in memory at location in I, the tens
                        // digit at location I+1, and the ones digit at
                        // location I+2.)

                        const DECIMAL_LENGTH: usize = 3;

                        let mut x: u8 = self.get_reg(regx);
                        let mut digits = vec![0 as u8; DECIMAL_LENGTH];
                        let mut digit_count: usize = 0;

                        // Organize the digits in the decimal into a slice.
                        while x > 0 {
                            digit_count += 1;
                            digits[DECIMAL_LENGTH - digit_count] = x % 10;
                            x /= 10;
                        }

                        // Set I, I+1, and I+3 to the values of the digits.
                        let i: usize = self.i as usize;
                        self.interconnect.ram[i] = digits[0];
                        self.interconnect.ram[i + 1] = digits[1];
                        self.interconnect.ram[i + 2] = digits[2];
                    },
                    0x65 => {
                        // FX65 - LD VX, [I]
                        //
                        // Fills V0 to VX with values from memory starting at
                        // address I.

                        let i: usize = self.i as usize;
                        let end_reg = (regx + 1) as usize;

                        for register in 0x0..end_reg {
                            let mem = self.interconnect.ram[i + register];
                            self.set_reg(register as u8, mem);
                        }
                    },
                    _ => {
                        println!("cpu: {:#?}", self);
                        panic!("Found unknown identifier at instruction: {:#x}, addr: {:#x}", instr, self.pc);
                    }
                }
            },
            _ => {
                println!("cpu: {:#?}", self);
                panic!("Found unknown opcode at instruction: {:#x}, addr: {:#x}", instr, self.pc);
            }
        }

        // Increment the program counter to the next instruction.
        self.pc += INSTRUCTION_SIZE;

        false
    }

    /// Gets the value at a specified register.
    fn get_reg(&mut self, reg: u8) -> u8 {
        match reg {
            0x0 => self.v0,
            0x1 => self.v1,
            0x2 => self.v2,
            0x3 => self.v3,
            0x4 => self.v4,
            0x5 => self.v5,
            0x6 => self.v6,
            0x7 => self.v7,
            0x8 => self.v8,
            0x9 => self.v9,
            0xa => self.va,
            0xb => self.vb,
            0xc => self.vc,
            0xd => self.vd,
            0xe => self.ve,
            0xf => self.vf,
            _ => {
                panic!("Cannot get unknown register: V{:X}", reg);
            }
        }
    }

    /// Sets the value of a general purpose register.
    fn set_reg(&mut self, reg: u8, byte: u8) {
        match reg {
            0x0 => self.v0 = byte,
            0x1 => self.v1 = byte,
            0x2 => self.v2 = byte,
            0x3 => self.v3 = byte,
            0x4 => self.v4 = byte,
            0x5 => self.v5 = byte,
            0x6 => self.v6 = byte,
            0x7 => self.v7 = byte,
            0x8 => self.v8 = byte,
            0x9 => self.v9 = byte,
            0xa => self.va = byte,
            0xb => self.vb = byte,
            0xc => self.vc = byte,
            0xd => self.vd = byte,
            0xe => self.ve = byte,
            0xf => self.vf = byte,
            _ => {
                panic!("Cannot set unknown register: V{:X}", reg);
            }
        }
    }
}
<|endoftext|>


<commit_before>//! Data structure serialization related stuff for RPC
//!
//! Defines all necessary rpc serialization data structures,
//! which includes `tt` related data and some task messages.
//! Although adding `Serialize` and `Deserialize` traits to `tt` directly seems
//! to be much easier, we deliberately duplicate `tt` structs with `#[serde(with = "XXDef")]`
//! for separation of code responsibility.
pub(crate) mod flat;

use std::path::PathBuf;

use serde::{Deserialize, Serialize};

use crate::rpc::flat::FlatTree;

#[derive(Clone, Eq, PartialEq, Debug, Serialize, Deserialize)]
pub struct ListMacrosTask {
    pub lib: PathBuf,
}

#[derive(Copy, Clone, Eq, PartialEq, Debug, Serialize, Deserialize)]
pub enum ProcMacroKind {
    CustomDerive,
    FuncLike,
    Attr,
}

#[derive(Clone, Eq, PartialEq, Debug, Default, Serialize, Deserialize)]
pub struct ListMacrosResult {
    pub macros: Vec<(String, ProcMacroKind)>,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct ExpansionTask {
    /// Argument of macro call.
    ///
    /// In custom derive this will be a struct or enum; in attribute-like macro - underlying
    /// item; in function-like macro - the macro body.
    pub macro_body: FlatTree,

    /// Name of macro to expand.
    ///
    /// In custom derive this is the name of the derived trait (`Serialize`, `Getters`, etc.).
    /// In attribute-like and function-like macros - single name of macro itself (`show_streams`).
    pub macro_name: String,

    /// Possible attributes for the attribute-like macros.
    pub attributes: Option<FlatTree>,

    pub lib: PathBuf,

    /// Environment variables to set during macro expansion.
    pub env: Vec<(String, String)>,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct ExpansionResult {
    pub expansion: FlatTree,
}

#[cfg(test)]
mod tests {
    use super::*;
    use tt::*;

    fn fixture_token_tree() -> Subtree {
        let mut subtree = Subtree::default();
        subtree
            .token_trees
            .push(TokenTree::Leaf(Ident { text: "struct".into(), id: TokenId(0) }.into()));
        subtree
            .token_trees
            .push(TokenTree::Leaf(Ident { text: "Foo".into(), id: TokenId(1) }.into()));
        subtree.token_trees.push(TokenTree::Leaf(Leaf::Literal(Literal {
            text: "Foo".into(),
            id: TokenId::unspecified(),
        })));
        subtree.token_trees.push(TokenTree::Leaf(Leaf::Punct(Punct {
            char: '@',
            id: TokenId::unspecified(),
            spacing: Spacing::Joint,
        })));
        subtree.token_trees.push(TokenTree::Subtree(Subtree {
            delimiter: Some(Delimiter { id: TokenId(2), kind: DelimiterKind::Brace }),
            token_trees: vec![],
        }));
        subtree
    }

    #[test]
    fn test_proc_macro_rpc_works() {
        let tt = fixture_token_tree();
        let task = ExpansionTask {
            macro_body: FlatTree::new(&tt),
            macro_name: Default::default(),
            attributes: None,
            lib: std::env::current_dir().unwrap(),
            env: Default::default(),
        };

        let json = serde_json::to_string(&task).unwrap();
        println!("{}", json);
        let back: ExpansionTask = serde_json::from_str(&json).unwrap();

        assert_eq!(tt, back.macro_body.to_subtree());
    }
}
<commit_msg>minor: remove debug print<commit_after>//! Data structure serialization related stuff for RPC
//!
//! Defines all necessary rpc serialization data structures,
//! which includes `tt` related data and some task messages.
//! Although adding `Serialize` and `Deserialize` traits to `tt` directly seems
//! to be much easier, we deliberately duplicate `tt` structs with `#[serde(with = "XXDef")]`
//! for separation of code responsibility.
pub(crate) mod flat;

use std::path::PathBuf;

use serde::{Deserialize, Serialize};

use crate::rpc::flat::FlatTree;

#[derive(Clone, Eq, PartialEq, Debug, Serialize, Deserialize)]
pub struct ListMacrosTask {
    pub lib: PathBuf,
}

#[derive(Copy, Clone, Eq, PartialEq, Debug, Serialize, Deserialize)]
pub enum ProcMacroKind {
    CustomDerive,
    FuncLike,
    Attr,
}

#[derive(Clone, Eq, PartialEq, Debug, Default, Serialize, Deserialize)]
pub struct ListMacrosResult {
    pub macros: Vec<(String, ProcMacroKind)>,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct ExpansionTask {
    /// Argument of macro call.
    ///
    /// In custom derive this will be a struct or enum; in attribute-like macro - underlying
    /// item; in function-like macro - the macro body.
    pub macro_body: FlatTree,

    /// Name of macro to expand.
    ///
    /// In custom derive this is the name of the derived trait (`Serialize`, `Getters`, etc.).
    /// In attribute-like and function-like macros - single name of macro itself (`show_streams`).
    pub macro_name: String,

    /// Possible attributes for the attribute-like macros.
    pub attributes: Option<FlatTree>,

    pub lib: PathBuf,

    /// Environment variables to set during macro expansion.
    pub env: Vec<(String, String)>,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct ExpansionResult {
    pub expansion: FlatTree,
}

#[cfg(test)]
mod tests {
    use super::*;
    use tt::*;

    fn fixture_token_tree() -> Subtree {
        let mut subtree = Subtree::default();
        subtree
            .token_trees
            .push(TokenTree::Leaf(Ident { text: "struct".into(), id: TokenId(0) }.into()));
        subtree
            .token_trees
            .push(TokenTree::Leaf(Ident { text: "Foo".into(), id: TokenId(1) }.into()));
        subtree.token_trees.push(TokenTree::Leaf(Leaf::Literal(Literal {
            text: "Foo".into(),
            id: TokenId::unspecified(),
        })));
        subtree.token_trees.push(TokenTree::Leaf(Leaf::Punct(Punct {
            char: '@',
            id: TokenId::unspecified(),
            spacing: Spacing::Joint,
        })));
        subtree.token_trees.push(TokenTree::Subtree(Subtree {
            delimiter: Some(Delimiter { id: TokenId(2), kind: DelimiterKind::Brace }),
            token_trees: vec![],
        }));
        subtree
    }

    #[test]
    fn test_proc_macro_rpc_works() {
        let tt = fixture_token_tree();
        let task = ExpansionTask {
            macro_body: FlatTree::new(&tt),
            macro_name: Default::default(),
            attributes: None,
            lib: std::env::current_dir().unwrap(),
            env: Default::default(),
        };

        let json = serde_json::to_string(&task).unwrap();
        // println!("{}", json);
        let back: ExpansionTask = serde_json::from_str(&json).unwrap();

        assert_eq!(tt, back.macro_body.to_subtree());
    }
}
<|endoftext|>


<commit_before>use libc::{c_int, c_char, uint32_t};

pub static MAX_CPUID_LEVEL: uint = 32u;
pub static MAX_EXT_CPUID_LEVEL: uint = 32u;
pub static MAX_INTELFN4_LEVEL: uint = 4u;
pub static MAX_INTELFN11_LEVEL: uint = 4u;
pub static VENDOR_STR_MAX: uint = 16u;
pub static BRAND_STR_MAX: uint = 64u;
pub static CPU_FLAGS_MAX: uint = 128u;
pub static CPU_HINTS_MAX: uint = 16u;

#[repr(C)]
pub struct cpu_raw_data_t {
    pub basic_cpuid: [[uint32_t, ..MAX_CPUID_LEVEL], ..4u],
    pub ext_cpuid: [[uint32_t, ..MAX_EXT_CPUID_LEVEL], ..4u],
    pub intel_fn4: [[uint32_t, ..MAX_INTELFN4_LEVEL], ..4u],
    pub intel_fn11: [[uint32_t, ..MAX_INTELFN11_LEVEL], ..4u],
}

// TODO: definition for struct cpu_id_t

#[link(name = "cpuid")]
extern {
    pub fn cpuid_present() -> c_int;
    pub fn cpuid_lib_version() -> *const c_char;
    pub fn cpuid_error() -> *const c_char;
    pub fn cpuid_get_raw_data(raw: *mut cpu_raw_data_t) -> c_int;
    // TODO: add cpu_identify
}
<commit_msg>Added cpu_id_t definition.<commit_after>use libc::{c_int, c_char, uint8_t, uint32_t, int32_t};

pub static MAX_CPUID_LEVEL: uint = 32u;
pub static MAX_EXT_CPUID_LEVEL: uint = 32u;
pub static MAX_INTELFN4_LEVEL: uint = 4u;
pub static MAX_INTELFN11_LEVEL: uint = 4u;
pub static VENDOR_STR_MAX: uint = 16u;
pub static BRAND_STR_MAX: uint = 64u;
pub static CPU_FLAGS_MAX: uint = 128u;
pub static CPU_HINTS_MAX: uint = 16u;

#[repr(C)]
pub struct cpu_raw_data_t {
    pub basic_cpuid: [[uint32_t, ..MAX_CPUID_LEVEL], ..4u],
    pub ext_cpuid: [[uint32_t, ..MAX_EXT_CPUID_LEVEL], ..4u],
    pub intel_fn4: [[uint32_t, ..MAX_INTELFN4_LEVEL], ..4u],
    pub intel_fn11: [[uint32_t, ..MAX_INTELFN11_LEVEL], ..4u],
}

#[repr(C)]
pub struct cpu_id_t {
    pub vendor_str: [c_char, ..VENDOR_STR_MAX],
    pub brand_str: [c_char, ..BRAND_STR_MAX],
    pub vendor: int32_t,
    pub flags: [uint8_t, ..CPU_FLAGS_MAX],
    pub family: int32_t,
    pub model: int32_t,
    pub stepping: int32_t,
    pub ext_family: int32_t,
    pub ext_model: int32_t,
    pub num_cores: int32_t,
    pub num_logical_cpus: int32_t,
    pub total_logical_cpus: int32_t,
    pub l1_data_cache: int32_t,
    pub l1_instruction_cache: int32_t,
    pub l2_cache: int32_t,
    pub l3_cache: int32_t,
    pub l1_assoc: int32_t,
    pub l2_assoc: int32_t,
    pub l3_assoc: int32_t,
    pub l1_cacheline: int32_t,
    pub l2_cacheline: int32_t,
    pub l3_cacheline: int32_t,
    pub cpu_codename: [c_char, ..64],
    pub sse_size: int32_t,
    pub detection_hints: [uint8_t, ..CPU_HINTS_MAX],
}

#[link(name = "cpuid")]
extern {
    pub fn cpuid_present() -> c_int;
    pub fn cpuid_lib_version() -> *const c_char;
    pub fn cpuid_error() -> *const c_char;
    pub fn cpuid_get_raw_data(raw: *mut cpu_raw_data_t) -> c_int;
    // TODO: add cpu_identify
}
<|endoftext|>


<commit_before>use std::time::SystemTime;

use anyhow::Context;
use aws_sigv4::{
    http_request::{self, SignableRequest, SigningSettings},
    SigningParams,
};
use reqwest::blocking::Client;
use retry::delay::{jitter, Exponential};
use retry::OperationResult;

#[derive(Clone)]
pub struct CloudFront {
    distribution_id: String,
    access_key: String,
    secret_key: String,
}

impl CloudFront {
    pub fn from_environment() -> Option<Self> {
        let distribution_id = dotenv::var("CLOUDFRONT_DISTRIBUTION").ok()?;
        let access_key = dotenv::var("AWS_ACCESS_KEY").expect("missing AWS_ACCESS_KEY");
        let secret_key = dotenv::var("AWS_SECRET_KEY").expect("missing AWS_SECRET_KEY");
        Some(Self {
            distribution_id,
            access_key,
            secret_key,
        })
    }

    /// Invalidate a file on CloudFront
    ///
    /// `path` is the path to the file to invalidate, such as `config.json`, or `re/ge/regex`
    #[instrument(skip(self, client))]
    pub fn invalidate(&self, client: &Client, path: &str) -> anyhow::Result<()> {
        let path = path.trim_start_matches('/');
        let url = format!(
            "https://cloudfront.amazonaws.com/2020-05-31/distribution/{}/invalidation",
            self.distribution_id
        );
        trace!(?url);

        let attempts = 10;
        let backoff = Exponential::from_millis(500).map(jitter).take(attempts - 1);
        retry::retry_with_index(backoff, |attempt| {
            let now = chrono::offset::Utc::now().timestamp_micros();
            let body = format!(
                r#"
<?xml version="1.0" encoding="UTF-8"?>
<InvalidationBatch xmlns="http://cloudfront.amazonaws.com/doc/2020-05-31/">
    <CallerReference>{now}</CallerReference>
    <Paths>
        <Items>
            <Path>/{path}</Path>
        </Items>
        <Quantity>1</Quantity>
    </Paths>
</InvalidationBatch>
"#
            );
            trace!(?body);

            let request = match http::Request::post(&url)
                .body(&body)
                .context("Failed to construct HTTP request")
            {
                Ok(request) => request,
                Err(error) => return OperationResult::Err(error),
            };

            trace!("Signing invalidation request");
            let request = SignableRequest::from(&request);
            let params = SigningParams::builder()
                .access_key(&self.access_key)
                .secret_key(&self.secret_key)
                .region("us-east-1") // cloudfront is a regionless service, use the default region for signing.
                .service_name("cloudfront")
                .settings(SigningSettings::default())
                .time(SystemTime::now())
                .build()
                .unwrap(); // all required fields are set

            let (mut signature_headers, _) =
                http_request::sign(request, &params).unwrap().into_parts();

            debug!(?attempt, "Sending invalidation request");
            let response = match client
                .post(&url)
                .headers(signature_headers.take_headers().unwrap_or_default())
                .body(body)
                .send()
                .context("Failed to send invalidation request")
            {
                Ok(response) => response,
                Err(error) => return OperationResult::Retry(error),
            };

            let status = response.status();

            let result = match response.error_for_status_ref() {
                Ok(_) => {
                    debug!(?status, "Invalidation request successful");
                    Ok(())
                }
                Err(error) => {
                    let headers = response.headers().clone();
                    let body = response.text();
                    debug!(?status, ?headers, ?body, "Invalidation request failed");

                    Err(error).with_context(|| format!("Failed to invalidate {path}"))
                }
            };

            match result {
                Ok(_) => OperationResult::Ok(()),
                Err(error) if status.is_server_error() => OperationResult::Retry(error),
                Err(error) => OperationResult::Err(error),
            }
        })
        .map_err(|error| error.error)
    }
}
<commit_msg>worker::cloudfront: Limit backoff to max. 30 sec.<commit_after>use std::time::{Duration, SystemTime};

use anyhow::Context;
use aws_sigv4::{
    http_request::{self, SignableRequest, SigningSettings},
    SigningParams,
};
use reqwest::blocking::Client;
use retry::delay::{jitter, Exponential};
use retry::OperationResult;

#[derive(Clone)]
pub struct CloudFront {
    distribution_id: String,
    access_key: String,
    secret_key: String,
}

impl CloudFront {
    pub fn from_environment() -> Option<Self> {
        let distribution_id = dotenv::var("CLOUDFRONT_DISTRIBUTION").ok()?;
        let access_key = dotenv::var("AWS_ACCESS_KEY").expect("missing AWS_ACCESS_KEY");
        let secret_key = dotenv::var("AWS_SECRET_KEY").expect("missing AWS_SECRET_KEY");
        Some(Self {
            distribution_id,
            access_key,
            secret_key,
        })
    }

    /// Invalidate a file on CloudFront
    ///
    /// `path` is the path to the file to invalidate, such as `config.json`, or `re/ge/regex`
    #[instrument(skip(self, client))]
    pub fn invalidate(&self, client: &Client, path: &str) -> anyhow::Result<()> {
        let path = path.trim_start_matches('/');
        let url = format!(
            "https://cloudfront.amazonaws.com/2020-05-31/distribution/{}/invalidation",
            self.distribution_id
        );
        trace!(?url);

        let attempts = 10;
        let backoff = Exponential::from_millis(500)
            .map(|duration| duration.clamp(Duration::ZERO, Duration::from_secs(30)))
            .map(jitter)
            .take(attempts - 1);

        retry::retry_with_index(backoff, |attempt| {
            let now = chrono::offset::Utc::now().timestamp_micros();
            let body = format!(
                r#"
<?xml version="1.0" encoding="UTF-8"?>
<InvalidationBatch xmlns="http://cloudfront.amazonaws.com/doc/2020-05-31/">
    <CallerReference>{now}</CallerReference>
    <Paths>
        <Items>
            <Path>/{path}</Path>
        </Items>
        <Quantity>1</Quantity>
    </Paths>
</InvalidationBatch>
"#
            );
            trace!(?body);

            let request = match http::Request::post(&url)
                .body(&body)
                .context("Failed to construct HTTP request")
            {
                Ok(request) => request,
                Err(error) => return OperationResult::Err(error),
            };

            trace!("Signing invalidation request");
            let request = SignableRequest::from(&request);
            let params = SigningParams::builder()
                .access_key(&self.access_key)
                .secret_key(&self.secret_key)
                .region("us-east-1") // cloudfront is a regionless service, use the default region for signing.
                .service_name("cloudfront")
                .settings(SigningSettings::default())
                .time(SystemTime::now())
                .build()
                .unwrap(); // all required fields are set

            let (mut signature_headers, _) =
                http_request::sign(request, &params).unwrap().into_parts();

            debug!(?attempt, "Sending invalidation request");
            let response = match client
                .post(&url)
                .headers(signature_headers.take_headers().unwrap_or_default())
                .body(body)
                .send()
                .context("Failed to send invalidation request")
            {
                Ok(response) => response,
                Err(error) => return OperationResult::Retry(error),
            };

            let status = response.status();

            let result = match response.error_for_status_ref() {
                Ok(_) => {
                    debug!(?status, "Invalidation request successful");
                    Ok(())
                }
                Err(error) => {
                    let headers = response.headers().clone();
                    let body = response.text();
                    debug!(?status, ?headers, ?body, "Invalidation request failed");

                    Err(error).with_context(|| format!("Failed to invalidate {path}"))
                }
            };

            match result {
                Ok(_) => OperationResult::Ok(()),
                Err(error) if status.is_server_error() => OperationResult::Retry(error),
                Err(error) => OperationResult::Err(error),
            }
        })
        .map_err(|error| error.error)
    }
}
<|endoftext|>


<commit_before>/*
Copyright (c) 2016-2017, Robert Ou <rqou@robertou.com> and contributors
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice,
   this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

use xc2bit::*;

use *;
use objpool::*;

pub fn produce_bitstream(device_type: XC2DeviceSpeedPackage, g: &InputGraph, go: &OutputGraph) -> XC2Bitstream {
    let mut result = XC2Bitstream::blank_bitstream(device_type);

    {
        let fb_bits = result.bits.get_fb_mut();

        // ZIA settings
        for fb_i in 0..go.zia.len() {
            for zia_i in 0..INPUTS_PER_ANDTERM {
                *fb_bits[fb_i].get_mut_zia(zia_i) = go.zia[fb_i].get(zia_i);
            }
        }

        // AND terms
        for andterm_idx in g.pterms.iter_idx() {
            let andterm_go = go.pterms.get(ObjPoolIndex::from(andterm_idx));
            let fb_i = andterm_go.loc.unwrap().fb as usize;
            let andterm_i = andterm_go.loc.unwrap().i as usize;

            for &x in &andterm_go.inputs_true_zia {
                fb_bits[fb_i].get_mut_andterm(andterm_i).set(x as usize, true);
            }
            for &x in &andterm_go.inputs_comp_zia {
                fb_bits[fb_i].get_mut_andterm(andterm_i).set_b(x as usize, true);
            }
        }
    }

    // IO bits
    for mc_idx in g.mcs.iter_idx() {
        let mc = g.mcs.get(mc_idx);
        let mc_go = go.mcs.get(ObjPoolIndex::from(mc_idx));
        let fb_i = mc_go.loc.unwrap().fb;
        let mc_i = mc_go.loc.unwrap().i;

        if let Some(ref io_bits) = mc.io_bits {
            if (device_type.dev == XC2Device::XC2C32 || device_type.dev == XC2Device::XC2C32A) && fb_i == 2 && mc_i == 0 {
                // Special input-only pin
                match result.bits {
                    XC2BitstreamBits::XC2C32{inpin: ref mut extra_inpin, ..} |
                    XC2BitstreamBits::XC2C32A{inpin: ref mut extra_inpin, ..} => {
                        extra_inpin.schmitt_trigger = io_bits.schmitt_trigger;
                        extra_inpin.termination_enabled = io_bits.termination_enabled;
                    },
                    _ => unreachable!(),
                }
            } else {
                let i_iob = fb_mc_num_to_iob_num(device_type.dev, fb_i as u32, mc_i as u32).unwrap();

                macro_rules! output_iob_common {
                    ($iob_bit:expr) => {{
                        $iob_bit.termination_enabled = io_bits.termination_enabled;
                        $iob_bit.slew_is_fast = io_bits.slew_is_fast;
                        if mc.io_feedback_used {
                            // We need to set the ZIA mode to use the IO pad.
                            $iob_bit.zia_mode = XC2IOBZIAMode::PAD;
                        } else if (mc.xor_feedback_used && mc.reg_feedback_used) ||
                            mc.get_type() == InputGraphMacrocellType::PinInputReg {

                            // If both of these are used, then the register _has_ to come from here. Otherwise use the
                            // "normal" one. Additionally, if we are a registered input pin, use the register.
                            $iob_bit.zia_mode = XC2IOBZIAMode::REG;
                        }
                        if let Some(input) = io_bits.input {
                            $iob_bit.obuf_uses_ff = input == InputGraphIOInputType::Reg;
                            $iob_bit.obuf_mode = match io_bits.oe {
                                None => XC2IOBOBufMode::PushPull,
                                Some(InputGraphIOOEType::OpenDrain) => XC2IOBOBufMode::OpenDrain,
                                Some(InputGraphIOOEType::PTerm(pterm)) => {
                                    let pterm = go.pterms.get(ObjPoolIndex::from(pterm));
                                    let pt_loc = pterm.loc.unwrap();
                                    assert!(pt_loc.fb == fb_i);

                                    if pt_loc.i == CTE {
                                        XC2IOBOBufMode::TriStateCTE
                                    } else if pt_loc.i == get_ptb(mc_i as u32) {
                                        XC2IOBOBufMode::TriStatePTB
                                    } else {
                                        panic!("Internal error - not CTE or PTB");
                                    }
                                },
                                Some(InputGraphIOOEType::GTS(gts)) => {
                                    let gts = go.bufg_gts.get(ObjPoolIndex::from(gts));
                                    let which = gts.loc.unwrap().i;
                                    match which {
                                        0 => XC2IOBOBufMode::TriStateGTS0,
                                        1 => XC2IOBOBufMode::TriStateGTS1,
                                        2 => XC2IOBOBufMode::TriStateGTS2,
                                        3 => XC2IOBOBufMode::TriStateGTS3,
                                        _ => panic!("Internal error - bad GTS"),
                                    }
                                },
                            }
                        }
                    }}
                }

                if device_type.dev.is_small_iob() {
                    let iob_bit = result.bits.get_mut_small_iob(i_iob as usize).unwrap();

                    iob_bit.schmitt_trigger = io_bits.schmitt_trigger;
                    output_iob_common!(iob_bit);
                } else {
                    let iob_bit = result.bits.get_mut_large_iob(i_iob as usize).unwrap();

                    // TODO: Pins that are/use Vref
                    iob_bit.ibuf_mode = if io_bits.schmitt_trigger {
                        XC2IOBIbufMode::NoVrefSt
                    } else {
                        XC2IOBIbufMode::NoVrefNoSt
                    };
                    iob_bit.uses_data_gate = io_bits.uses_data_gate;
                    output_iob_common!(iob_bit);
                }
            }
        }
    }

    {
        let fb_bits = result.bits.get_fb_mut();

        // OR/XOR gates
        for mc_idx in g.mcs.iter_idx() {
            let mc = g.mcs.get(mc_idx);
            let mc_go = go.mcs.get(ObjPoolIndex::from(mc_idx));
            let fb_i = mc_go.loc.unwrap().fb as usize;
            let mc_i = mc_go.loc.unwrap().i as usize;

            if let Some(ref xor_bits) = mc.xor_bits {
                // XOR
                fb_bits[fb_i].mcs[mc_i].xor_mode = match (xor_bits.invert_out, xor_bits.andterm_input) {
                    (false, None) => XC2MCXorMode::ZERO,
                    (true, None) => XC2MCXorMode::ONE,
                    (false, Some(_)) => XC2MCXorMode::PTC,
                    (true, Some(_)) => XC2MCXorMode::PTCB,
                };

                // OR
                for &and_to_or_idx in &xor_bits.orterm_inputs {
                    let pterm = go.pterms.get(ObjPoolIndex::from(and_to_or_idx));
                    let pt_loc = pterm.loc.unwrap();
                    assert!(pt_loc.fb as usize == fb_i);
                    fb_bits[fb_i].or_terms[mc_i].set(pt_loc.i as usize, true);
                }

                // Feedback
                if mc.xor_feedback_used {
                    fb_bits[fb_i].mcs[mc_i].fb_mode = XC2MCFeedbackMode::COMB;
                } else if mc.reg_feedback_used {
                    fb_bits[fb_i].mcs[mc_i].fb_mode = XC2MCFeedbackMode::REG;
                }
            }
        }

        // Register bits
        for mc_idx in g.mcs.iter_idx() {
            let mc = g.mcs.get(mc_idx);
            let mc_go = go.mcs.get(ObjPoolIndex::from(mc_idx));
            let fb_i = mc_go.loc.unwrap().fb as usize;
            let mc_i = mc_go.loc.unwrap().i as usize;

            if let Some(ref reg_bits) = mc.reg_bits {
                fb_bits[fb_i].mcs[mc_i].reg_mode = reg_bits.mode;
                fb_bits[fb_i].mcs[mc_i].clk_invert_pol = reg_bits.clkinv;
                fb_bits[fb_i].mcs[mc_i].is_ddr = reg_bits.clkddr;
                fb_bits[fb_i].mcs[mc_i].init_state = reg_bits.init_state;

                // Set
                fb_bits[fb_i].mcs[mc_i].s_src = match reg_bits.set_input {
                    None => XC2MCRegSetSrc::Disabled,
                    Some(InputGraphRegRSType::GSR(_)) => XC2MCRegSetSrc::GSR,
                    Some(InputGraphRegRSType::PTerm(pterm)) => {
                        let pterm = go.pterms.get(ObjPoolIndex::from(pterm));
                        let pt_loc = pterm.loc.unwrap();
                        assert!(pt_loc.fb as usize == fb_i);

                        if pt_loc.i == CTS {
                            XC2MCRegSetSrc::CTS
                        } else if pt_loc.i == get_pta(mc_i as u32) {
                            XC2MCRegSetSrc::PTA
                        } else {
                            panic!("Internal error - not CTS or PTA");
                        }
                    },
                };

                // Reset
                fb_bits[fb_i].mcs[mc_i].r_src = match reg_bits.reset_input {
                    None => XC2MCRegResetSrc::Disabled,
                    Some(InputGraphRegRSType::GSR(_)) => XC2MCRegResetSrc::GSR,
                    Some(InputGraphRegRSType::PTerm(pterm)) => {
                        let pterm = go.pterms.get(ObjPoolIndex::from(pterm));
                        let pt_loc = pterm.loc.unwrap();
                        assert!(pt_loc.fb as usize == fb_i);

                        if pt_loc.i == CTR {
                            XC2MCRegResetSrc::CTR
                        } else if pt_loc.i == get_pta(mc_i as u32) {
                            XC2MCRegResetSrc::PTA
                        } else {
                            panic!("Internal error - not CTR or PTA");
                        }
                    },
                };

                // D/T input
                fb_bits[fb_i].mcs[mc_i].ff_in_ibuf = reg_bits.dt_input == InputGraphRegInputType::Pin;

                // Clock input
                fb_bits[fb_i].mcs[mc_i].clk_src = match reg_bits.clk_input {
                    InputGraphRegClockType::PTerm(pterm) => {
                        let pterm = go.pterms.get(ObjPoolIndex::from(pterm));
                        let pt_loc = pterm.loc.unwrap();
                        assert!(pt_loc.fb as usize == fb_i);

                        if pt_loc.i == CTC {
                            XC2MCRegClkSrc::CTC
                        } else if pt_loc.i == get_ptc(mc_i as u32) {
                            XC2MCRegClkSrc::PTC
                        } else {
                            panic!("Internal error - not CTC or PTC");
                        }
                    },
                    InputGraphRegClockType::GCK(gck) => {
                        let gck = go.bufg_clks.get(ObjPoolIndex::from(gck));
                        let which = gck.loc.unwrap().i;
                        match which {
                            0 => XC2MCRegClkSrc::GCK0,
                            1 => XC2MCRegClkSrc::GCK1,
                            2 => XC2MCRegClkSrc::GCK2,
                            _ => panic!("Internal error - bad GCK"),
                        }
                    },
                }
            }
        }
    }

    {
        let global_nets = result.bits.get_global_nets_mut();

        // Global buffers
        for gck in go.bufg_clks.iter() {
            let which = gck.loc.unwrap().i;
            global_nets.gck_enable[which as usize] = true;
        }
        for gts_idx in g.bufg_gts.iter_idx() {
            let gts = g.bufg_gts.get(gts_idx);
            let gts_go = go.bufg_gts.get(ObjPoolIndex::from(gts_idx));
            let which = gts_go.loc.unwrap().i;
            global_nets.gts_enable[which as usize] = true;
            global_nets.gts_invert[which as usize] = gts.invert;
        }
        for gsr in g.bufg_gsr.iter() {
            global_nets.gsr_enable = true;
            global_nets.gsr_invert = gsr.invert;
        }
    }

    // XXX TODO other global bits
    if let XC2BitstreamBits::XC2C32A{ref mut legacy_ivoltage, ref mut legacy_ovoltage,
        ref mut ivoltage, ref mut ovoltage, ..} = result.bits {

        *legacy_ivoltage = false;
        *legacy_ovoltage = false;
        *ivoltage = [false, false];
        *ovoltage = [false, false];
    }

    result
}
<commit_msg>xc2par: Fix using reg+xor feedback if io unused<commit_after>/*
Copyright (c) 2016-2017, Robert Ou <rqou@robertou.com> and contributors
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice,
   this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

use xc2bit::*;

use *;
use objpool::*;

pub fn produce_bitstream(device_type: XC2DeviceSpeedPackage, g: &InputGraph, go: &OutputGraph) -> XC2Bitstream {
    let mut result = XC2Bitstream::blank_bitstream(device_type);

    {
        let fb_bits = result.bits.get_fb_mut();

        // ZIA settings
        for fb_i in 0..go.zia.len() {
            for zia_i in 0..INPUTS_PER_ANDTERM {
                *fb_bits[fb_i].get_mut_zia(zia_i) = go.zia[fb_i].get(zia_i);
            }
        }

        // AND terms
        for andterm_idx in g.pterms.iter_idx() {
            let andterm_go = go.pterms.get(ObjPoolIndex::from(andterm_idx));
            let fb_i = andterm_go.loc.unwrap().fb as usize;
            let andterm_i = andterm_go.loc.unwrap().i as usize;

            for &x in &andterm_go.inputs_true_zia {
                fb_bits[fb_i].get_mut_andterm(andterm_i).set(x as usize, true);
            }
            for &x in &andterm_go.inputs_comp_zia {
                fb_bits[fb_i].get_mut_andterm(andterm_i).set_b(x as usize, true);
            }
        }
    }

    // IO bits
    for mc_idx in g.mcs.iter_idx() {
        let mc = g.mcs.get(mc_idx);
        let mc_go = go.mcs.get(ObjPoolIndex::from(mc_idx));
        let fb_i = mc_go.loc.unwrap().fb;
        let mc_i = mc_go.loc.unwrap().i;

        if let Some(ref io_bits) = mc.io_bits {
            if (device_type.dev == XC2Device::XC2C32 || device_type.dev == XC2Device::XC2C32A) && fb_i == 2 && mc_i == 0 {
                // Special input-only pin
                match result.bits {
                    XC2BitstreamBits::XC2C32{inpin: ref mut extra_inpin, ..} |
                    XC2BitstreamBits::XC2C32A{inpin: ref mut extra_inpin, ..} => {
                        extra_inpin.schmitt_trigger = io_bits.schmitt_trigger;
                        extra_inpin.termination_enabled = io_bits.termination_enabled;
                    },
                    _ => unreachable!(),
                }
            } else {
                let i_iob = fb_mc_num_to_iob_num(device_type.dev, fb_i as u32, mc_i as u32).unwrap();

                macro_rules! output_iob_common {
                    ($iob_bit:expr) => {{
                        $iob_bit.termination_enabled = io_bits.termination_enabled;
                        $iob_bit.slew_is_fast = io_bits.slew_is_fast;
                        if let Some(input) = io_bits.input {
                            $iob_bit.obuf_uses_ff = input == InputGraphIOInputType::Reg;
                            $iob_bit.obuf_mode = match io_bits.oe {
                                None => XC2IOBOBufMode::PushPull,
                                Some(InputGraphIOOEType::OpenDrain) => XC2IOBOBufMode::OpenDrain,
                                Some(InputGraphIOOEType::PTerm(pterm)) => {
                                    let pterm = go.pterms.get(ObjPoolIndex::from(pterm));
                                    let pt_loc = pterm.loc.unwrap();
                                    assert!(pt_loc.fb == fb_i);

                                    if pt_loc.i == CTE {
                                        XC2IOBOBufMode::TriStateCTE
                                    } else if pt_loc.i == get_ptb(mc_i as u32) {
                                        XC2IOBOBufMode::TriStatePTB
                                    } else {
                                        panic!("Internal error - not CTE or PTB");
                                    }
                                },
                                Some(InputGraphIOOEType::GTS(gts)) => {
                                    let gts = go.bufg_gts.get(ObjPoolIndex::from(gts));
                                    let which = gts.loc.unwrap().i;
                                    match which {
                                        0 => XC2IOBOBufMode::TriStateGTS0,
                                        1 => XC2IOBOBufMode::TriStateGTS1,
                                        2 => XC2IOBOBufMode::TriStateGTS2,
                                        3 => XC2IOBOBufMode::TriStateGTS3,
                                        _ => panic!("Internal error - bad GTS"),
                                    }
                                },
                            }
                        }
                    }}
                }

                if device_type.dev.is_small_iob() {
                    let iob_bit = result.bits.get_mut_small_iob(i_iob as usize).unwrap();

                    iob_bit.schmitt_trigger = io_bits.schmitt_trigger;
                    output_iob_common!(iob_bit);
                } else {
                    let iob_bit = result.bits.get_mut_large_iob(i_iob as usize).unwrap();

                    // TODO: Pins that are/use Vref
                    iob_bit.ibuf_mode = if io_bits.schmitt_trigger {
                        XC2IOBIbufMode::NoVrefSt
                    } else {
                        XC2IOBIbufMode::NoVrefNoSt
                    };
                    iob_bit.uses_data_gate = io_bits.uses_data_gate;
                    output_iob_common!(iob_bit);
                }
            }
        }

        // Set the ZIA feedback mode (even if the io bit isn't actually used)
        if let Some(i_iob) = fb_mc_num_to_iob_num(device_type.dev, fb_i as u32, mc_i as u32) {
            macro_rules! output_iob_common {
                ($iob_bit:expr) => {{
                    if mc.io_feedback_used {
                        // We need to set the ZIA mode to use the IO pad.
                        $iob_bit.zia_mode = XC2IOBZIAMode::PAD;
                    } else if (mc.xor_feedback_used && mc.reg_feedback_used) ||
                        mc.get_type() == InputGraphMacrocellType::PinInputReg {

                        // If both of these are used, then the register _has_ to come from here. Otherwise use the
                        // "normal" one. Additionally, if we are a registered input pin, use the register.
                        $iob_bit.zia_mode = XC2IOBZIAMode::REG;
                    }
                }}
            }

            if device_type.dev.is_small_iob() {
                let iob_bit = result.bits.get_mut_small_iob(i_iob as usize).unwrap();

                output_iob_common!(iob_bit);
            } else {
                let iob_bit = result.bits.get_mut_large_iob(i_iob as usize).unwrap();

                output_iob_common!(iob_bit);
            }
        }
    }

    {
        let fb_bits = result.bits.get_fb_mut();

        // OR/XOR gates
        for mc_idx in g.mcs.iter_idx() {
            let mc = g.mcs.get(mc_idx);
            let mc_go = go.mcs.get(ObjPoolIndex::from(mc_idx));
            let fb_i = mc_go.loc.unwrap().fb as usize;
            let mc_i = mc_go.loc.unwrap().i as usize;

            if let Some(ref xor_bits) = mc.xor_bits {
                // XOR
                fb_bits[fb_i].mcs[mc_i].xor_mode = match (xor_bits.invert_out, xor_bits.andterm_input) {
                    (false, None) => XC2MCXorMode::ZERO,
                    (true, None) => XC2MCXorMode::ONE,
                    (false, Some(_)) => XC2MCXorMode::PTC,
                    (true, Some(_)) => XC2MCXorMode::PTCB,
                };

                // OR
                for &and_to_or_idx in &xor_bits.orterm_inputs {
                    let pterm = go.pterms.get(ObjPoolIndex::from(and_to_or_idx));
                    let pt_loc = pterm.loc.unwrap();
                    assert!(pt_loc.fb as usize == fb_i);
                    fb_bits[fb_i].or_terms[mc_i].set(pt_loc.i as usize, true);
                }

                // Feedback
                if mc.xor_feedback_used {
                    fb_bits[fb_i].mcs[mc_i].fb_mode = XC2MCFeedbackMode::COMB;
                } else if mc.reg_feedback_used {
                    fb_bits[fb_i].mcs[mc_i].fb_mode = XC2MCFeedbackMode::REG;
                }
            }
        }

        // Register bits
        for mc_idx in g.mcs.iter_idx() {
            let mc = g.mcs.get(mc_idx);
            let mc_go = go.mcs.get(ObjPoolIndex::from(mc_idx));
            let fb_i = mc_go.loc.unwrap().fb as usize;
            let mc_i = mc_go.loc.unwrap().i as usize;

            if let Some(ref reg_bits) = mc.reg_bits {
                fb_bits[fb_i].mcs[mc_i].reg_mode = reg_bits.mode;
                fb_bits[fb_i].mcs[mc_i].clk_invert_pol = reg_bits.clkinv;
                fb_bits[fb_i].mcs[mc_i].is_ddr = reg_bits.clkddr;
                fb_bits[fb_i].mcs[mc_i].init_state = reg_bits.init_state;

                // Set
                fb_bits[fb_i].mcs[mc_i].s_src = match reg_bits.set_input {
                    None => XC2MCRegSetSrc::Disabled,
                    Some(InputGraphRegRSType::GSR(_)) => XC2MCRegSetSrc::GSR,
                    Some(InputGraphRegRSType::PTerm(pterm)) => {
                        let pterm = go.pterms.get(ObjPoolIndex::from(pterm));
                        let pt_loc = pterm.loc.unwrap();
                        assert!(pt_loc.fb as usize == fb_i);

                        if pt_loc.i == CTS {
                            XC2MCRegSetSrc::CTS
                        } else if pt_loc.i == get_pta(mc_i as u32) {
                            XC2MCRegSetSrc::PTA
                        } else {
                            panic!("Internal error - not CTS or PTA");
                        }
                    },
                };

                // Reset
                fb_bits[fb_i].mcs[mc_i].r_src = match reg_bits.reset_input {
                    None => XC2MCRegResetSrc::Disabled,
                    Some(InputGraphRegRSType::GSR(_)) => XC2MCRegResetSrc::GSR,
                    Some(InputGraphRegRSType::PTerm(pterm)) => {
                        let pterm = go.pterms.get(ObjPoolIndex::from(pterm));
                        let pt_loc = pterm.loc.unwrap();
                        assert!(pt_loc.fb as usize == fb_i);

                        if pt_loc.i == CTR {
                            XC2MCRegResetSrc::CTR
                        } else if pt_loc.i == get_pta(mc_i as u32) {
                            XC2MCRegResetSrc::PTA
                        } else {
                            panic!("Internal error - not CTR or PTA");
                        }
                    },
                };

                // D/T input
                fb_bits[fb_i].mcs[mc_i].ff_in_ibuf = reg_bits.dt_input == InputGraphRegInputType::Pin;

                // Clock input
                fb_bits[fb_i].mcs[mc_i].clk_src = match reg_bits.clk_input {
                    InputGraphRegClockType::PTerm(pterm) => {
                        let pterm = go.pterms.get(ObjPoolIndex::from(pterm));
                        let pt_loc = pterm.loc.unwrap();
                        assert!(pt_loc.fb as usize == fb_i);

                        if pt_loc.i == CTC {
                            XC2MCRegClkSrc::CTC
                        } else if pt_loc.i == get_ptc(mc_i as u32) {
                            XC2MCRegClkSrc::PTC
                        } else {
                            panic!("Internal error - not CTC or PTC");
                        }
                    },
                    InputGraphRegClockType::GCK(gck) => {
                        let gck = go.bufg_clks.get(ObjPoolIndex::from(gck));
                        let which = gck.loc.unwrap().i;
                        match which {
                            0 => XC2MCRegClkSrc::GCK0,
                            1 => XC2MCRegClkSrc::GCK1,
                            2 => XC2MCRegClkSrc::GCK2,
                            _ => panic!("Internal error - bad GCK"),
                        }
                    },
                }
            }
        }
    }

    {
        let global_nets = result.bits.get_global_nets_mut();

        // Global buffers
        for gck in go.bufg_clks.iter() {
            let which = gck.loc.unwrap().i;
            global_nets.gck_enable[which as usize] = true;
        }
        for gts_idx in g.bufg_gts.iter_idx() {
            let gts = g.bufg_gts.get(gts_idx);
            let gts_go = go.bufg_gts.get(ObjPoolIndex::from(gts_idx));
            let which = gts_go.loc.unwrap().i;
            global_nets.gts_enable[which as usize] = true;
            global_nets.gts_invert[which as usize] = gts.invert;
        }
        for gsr in g.bufg_gsr.iter() {
            global_nets.gsr_enable = true;
            global_nets.gsr_invert = gsr.invert;
        }
    }

    // XXX TODO other global bits
    if let XC2BitstreamBits::XC2C32A{ref mut legacy_ivoltage, ref mut legacy_ovoltage,
        ref mut ivoltage, ref mut ovoltage, ..} = result.bits {

        *legacy_ivoltage = false;
        *legacy_ovoltage = false;
        *ivoltage = [false, false];
        *ovoltage = [false, false];
    }

    result
}
<|endoftext|>