<commit_before>// Copyright 2015 Philipp Oppermann. See the README.md
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

pub use self::entry::*;
use memory::{PAGE_SIZE, Frame, FrameAllocator};
use self::temporary_page::TemporaryPage;
pub use self::mapper::Mapper;
use core::ops::{Deref, DerefMut};
use multiboot2::BootInformation;

mod entry;
mod table;
mod temporary_page;
mod mapper;

const ENTRY_COUNT: usize = 512;

pub type PhysicalAddress = usize;
pub type VirtualAddress = usize;

#[derive(Debug, Clone, Copy)]
pub struct Page {
    number: usize,
}

impl Page {
    pub fn containing_address(address: VirtualAddress) -> Page {
        assert!(address < 0x0000_8000_0000_0000 || address >= 0xffff_8000_0000_0000,
                "invalid address: 0x{:x}",
                address);
        Page { number: address / PAGE_SIZE }
    }

    fn start_address(&self) -> usize {
        self.number * PAGE_SIZE
    }

    fn p4_index(&self) -> usize {
        (self.number >> 27) & 0o777
    }
    fn p3_index(&self) -> usize {
        (self.number >> 18) & 0o777
    }
    fn p2_index(&self) -> usize {
        (self.number >> 9) & 0o777
    }
    fn p1_index(&self) -> usize {
        (self.number >> 0) & 0o777
    }
}

pub struct ActivePageTable {
    mapper: Mapper,
}

impl Deref for ActivePageTable {
    type Target = Mapper;

    fn deref(&self) -> &Mapper {
        &self.mapper
    }
}

impl DerefMut for ActivePageTable {
    fn deref_mut(&mut self) -> &mut Mapper {
        &mut self.mapper
    }
}

impl ActivePageTable {
    unsafe fn new() -> ActivePageTable {
        ActivePageTable { mapper: Mapper::new() }
    }

    pub fn with<F>(&mut self,
                   table: &mut InactivePageTable,
                   temporary_page: &mut temporary_page::TemporaryPage, // new
                   f: F)
        where F: FnOnce(&mut Mapper)
    {
        use x86::{controlregs, tlb};
        let flush_tlb = || unsafe { tlb::flush_all() };

        {
            let backup = Frame::containing_address(unsafe { controlregs::cr3() } as usize);

            // map temporary_page to current p4 table
            let p4_table = temporary_page.map_table_frame(backup.clone(), self);

            // overwrite recursive mapping
            self.p4_mut()[511].set(table.p4_frame.clone(), PRESENT | WRITABLE);
            flush_tlb();

            // execute f in the new context
            f(self);

            // restore recursive mapping to original p4 table
            p4_table[511].set(backup, PRESENT | WRITABLE);
            flush_tlb();
        }

        temporary_page.unmap(self);
    }

    pub fn switch(&mut self, new_table: InactivePageTable) -> InactivePageTable {
        use x86::controlregs;

        let old_table = InactivePageTable {
            p4_frame: Frame::containing_address(unsafe { controlregs::cr3() } as usize),
        };
        unsafe {
            controlregs::cr3_write(new_table.p4_frame.start_address() as u64);
        }
        old_table
    }
}

pub struct InactivePageTable {
    p4_frame: Frame,
}

impl InactivePageTable {
    pub fn new(frame: Frame,
               active_table: &mut ActivePageTable,
               temporary_page: &mut TemporaryPage)
               -> InactivePageTable {
        {
            let table = temporary_page.map_table_frame(frame.clone(), active_table);
            table.zero();
            table[511].set(frame.clone(), PRESENT | WRITABLE);
        }
        temporary_page.unmap(active_table);

        InactivePageTable { p4_frame: frame }
    }
}

pub fn remap_the_kernel<A>(allocator: &mut A, boot_info: &BootInformation)
    where A: FrameAllocator
{
    use core::ops::Range;

    let mut temporary_page = TemporaryPage::new(Page { number: 0xcafebabe }, allocator);

    let mut active_table = unsafe { ActivePageTable::new() };
    let mut new_table = {
        let frame = allocator.allocate_frame().expect("no more frames");
        InactivePageTable::new(frame, &mut active_table, &mut temporary_page)
    };

    active_table.with(&mut new_table, &mut temporary_page, |mapper| {
        let elf_sections_tag = boot_info.elf_sections_tag()
                                        .expect("Memory map tag required");

        // identity map the allocated kernel sections
        for section in elf_sections_tag.sections() {
            use multiboot2::ELF_SECTION_ALLOCATED;

            if !section.flags().contains(ELF_SECTION_ALLOCATED) {
                // section is not loaded to memory
                continue;
            }

            println!("mapping section at addr: {:#x}, size: {:#x}",
                     section.addr,
                     section.size);

            let flags = EntryFlags::from_elf_section_flags(section);

            let range = Range {
                start: section.addr as usize,
                end: (section.addr + section.size) as usize,
            };
            for address in range.step_by(PAGE_SIZE) {
                assert!(address % PAGE_SIZE == 0, "sections need to be page aligned");
                let frame = Frame::containing_address(address);
                mapper.identity_map(frame, flags, allocator);
            }
        }

        // identity map the VGA text buffer
        let vga_buffer_frame = Frame::containing_address(0xb8000);
        mapper.identity_map(vga_buffer_frame, WRITABLE, allocator);

        // identity map the multiboot info structure
        let multiboot_start = boot_info as *const _ as usize;
        let range = Range {
            start: multiboot_start,
            end: multiboot_start + (boot_info.total_size as usize),
        };
        for address in range.step_by(PAGE_SIZE) {
            mapper.identity_map(Frame::containing_address(address), PRESENT, allocator);
        }
    });

    let old_table = active_table.switch(new_table);
    println!("NEW TABLE!!!");

    let old_p4_page = Page::containing_address(old_table.p4_frame.start_address());
    active_table.unmap(old_p4_page, allocator);
    println!("guard page at {:#x}", old_p4_page.start_address());
}
<commit_msg>Use new `section.is_allocated` function<commit_after>// Copyright 2015 Philipp Oppermann. See the README.md
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

pub use self::entry::*;
use memory::{PAGE_SIZE, Frame, FrameAllocator};
use self::temporary_page::TemporaryPage;
pub use self::mapper::Mapper;
use core::ops::{Deref, DerefMut};
use multiboot2::BootInformation;

mod entry;
mod table;
mod temporary_page;
mod mapper;

const ENTRY_COUNT: usize = 512;

pub type PhysicalAddress = usize;
pub type VirtualAddress = usize;

#[derive(Debug, Clone, Copy)]
pub struct Page {
    number: usize,
}

impl Page {
    pub fn containing_address(address: VirtualAddress) -> Page {
        assert!(address < 0x0000_8000_0000_0000 || address >= 0xffff_8000_0000_0000,
                "invalid address: 0x{:x}",
                address);
        Page { number: address / PAGE_SIZE }
    }

    fn start_address(&self) -> usize {
        self.number * PAGE_SIZE
    }

    fn p4_index(&self) -> usize {
        (self.number >> 27) & 0o777
    }
    fn p3_index(&self) -> usize {
        (self.number >> 18) & 0o777
    }
    fn p2_index(&self) -> usize {
        (self.number >> 9) & 0o777
    }
    fn p1_index(&self) -> usize {
        (self.number >> 0) & 0o777
    }
}

pub struct ActivePageTable {
    mapper: Mapper,
}

impl Deref for ActivePageTable {
    type Target = Mapper;

    fn deref(&self) -> &Mapper {
        &self.mapper
    }
}

impl DerefMut for ActivePageTable {
    fn deref_mut(&mut self) -> &mut Mapper {
        &mut self.mapper
    }
}

impl ActivePageTable {
    unsafe fn new() -> ActivePageTable {
        ActivePageTable { mapper: Mapper::new() }
    }

    pub fn with<F>(&mut self,
                   table: &mut InactivePageTable,
                   temporary_page: &mut temporary_page::TemporaryPage, // new
                   f: F)
        where F: FnOnce(&mut Mapper)
    {
        use x86::{controlregs, tlb};
        let flush_tlb = || unsafe { tlb::flush_all() };

        {
            let backup = Frame::containing_address(unsafe { controlregs::cr3() } as usize);

            // map temporary_page to current p4 table
            let p4_table = temporary_page.map_table_frame(backup.clone(), self);

            // overwrite recursive mapping
            self.p4_mut()[511].set(table.p4_frame.clone(), PRESENT | WRITABLE);
            flush_tlb();

            // execute f in the new context
            f(self);

            // restore recursive mapping to original p4 table
            p4_table[511].set(backup, PRESENT | WRITABLE);
            flush_tlb();
        }

        temporary_page.unmap(self);
    }

    pub fn switch(&mut self, new_table: InactivePageTable) -> InactivePageTable {
        use x86::controlregs;

        let old_table = InactivePageTable {
            p4_frame: Frame::containing_address(unsafe { controlregs::cr3() } as usize),
        };
        unsafe {
            controlregs::cr3_write(new_table.p4_frame.start_address() as u64);
        }
        old_table
    }
}

pub struct InactivePageTable {
    p4_frame: Frame,
}

impl InactivePageTable {
    pub fn new(frame: Frame,
               active_table: &mut ActivePageTable,
               temporary_page: &mut TemporaryPage)
               -> InactivePageTable {
        {
            let table = temporary_page.map_table_frame(frame.clone(), active_table);
            table.zero();
            table[511].set(frame.clone(), PRESENT | WRITABLE);
        }
        temporary_page.unmap(active_table);

        InactivePageTable { p4_frame: frame }
    }
}

pub fn remap_the_kernel<A>(allocator: &mut A, boot_info: &BootInformation)
    where A: FrameAllocator
{
    use core::ops::Range;

    let mut temporary_page = TemporaryPage::new(Page { number: 0xcafebabe }, allocator);

    let mut active_table = unsafe { ActivePageTable::new() };
    let mut new_table = {
        let frame = allocator.allocate_frame().expect("no more frames");
        InactivePageTable::new(frame, &mut active_table, &mut temporary_page)
    };

    active_table.with(&mut new_table, &mut temporary_page, |mapper| {
        let elf_sections_tag = boot_info.elf_sections_tag()
                                        .expect("Memory map tag required");

        // identity map the allocated kernel sections
        for section in elf_sections_tag.sections() {
            if !section.is_allocated() {
                // section is not loaded to memory
                continue;
            }

            println!("mapping section at addr: {:#x}, size: {:#x}",
                     section.addr,
                     section.size);

            let flags = EntryFlags::from_elf_section_flags(section);

            let range = Range {
                start: section.addr as usize,
                end: (section.addr + section.size) as usize,
            };
            for address in range.step_by(PAGE_SIZE) {
                assert!(address % PAGE_SIZE == 0, "sections need to be page aligned");
                let frame = Frame::containing_address(address);
                mapper.identity_map(frame, flags, allocator);
            }
        }

        // identity map the VGA text buffer
        let vga_buffer_frame = Frame::containing_address(0xb8000);
        mapper.identity_map(vga_buffer_frame, WRITABLE, allocator);

        // identity map the multiboot info structure
        let multiboot_start = boot_info as *const _ as usize;
        let range = Range {
            start: multiboot_start,
            end: multiboot_start + (boot_info.total_size as usize),
        };
        for address in range.step_by(PAGE_SIZE) {
            mapper.identity_map(Frame::containing_address(address), PRESENT, allocator);
        }
    });

    let old_table = active_table.switch(new_table);
    println!("NEW TABLE!!!");

    let old_p4_page = Page::containing_address(old_table.p4_frame.start_address());
    active_table.unmap(old_p4_page, allocator);
    println!("guard page at {:#x}", old_p4_page.start_address());
}
<|endoftext|>


<commit_before>mod entry;
mod table;
pub mod translate;
pub mod mapping;
pub mod lock;

pub fn test<A>(frame_allocator: &mut A)
    where A: super::FrameAllocator
{
    use self::entry::PRESENT;
    mapping::map(&Page::containing_address(0xdeadbeaa000),
                 PRESENT,
                 frame_allocator);
    mapping::map(&Page::containing_address(0xdeadbeab000),
                 PRESENT,
                 frame_allocator);
    mapping::map(&Page::containing_address(0xdeadbeac000),
                 PRESENT,
                 frame_allocator);
    mapping::map(&Page::containing_address(0xdeadbead000),
                 PRESENT,
                 frame_allocator);
    mapping::map(&Page::containing_address(0xcafebeaf000),
                 PRESENT,
                 frame_allocator);
    mapping::map(&Page::containing_address(0x0),
                 PRESENT,
                 frame_allocator);
}

pub const PAGE_SIZE: usize = 4096;
const ENTRY_COUNT: usize = 512;

pub type PhysicalAddress = usize;
pub type VirtualAddress = usize;

pub struct Page {
    number: usize,
}

impl Page {
    fn containing_address(address: VirtualAddress) -> Page {
        match address {
            addr if addr < 0o_400_000_000_000_0000 => Page { number: addr / PAGE_SIZE },
            addr if addr >= 0o177777_400_000_000_000_0000 => {
                Page { number: (address / PAGE_SIZE) & 0o_777_777_777_777 }
            }
            _ => panic!("invalid address: 0x{:x}", address),
        }
    }

    pub fn start_address(&self) -> VirtualAddress {
        if self.number >= 0x800000000 {
            // sign extension necessary
            (self.number << 12) | 0xffff_000000000000
        } else {
            self.number << 12
        }
    }

    fn p4_index(&self) -> usize {
        (self.number >> 27) & 0o777
    }
    fn p3_index(&self) -> usize {
        (self.number >> 18) & 0o777
    }
    fn p2_index(&self) -> usize {
        (self.number >> 9) & 0o777
    }
    fn p1_index(&self) -> usize {
        (self.number >> 0) & 0o777
    }
}
<commit_msg>Change semantics of `start_address` and `containing_address`<commit_after>mod entry;
mod table;
pub mod translate;
pub mod mapping;
pub mod lock;

pub fn test<A>(frame_allocator: &mut A)
    where A: super::FrameAllocator
{
    use self::entry::PRESENT;
    mapping::map(&Page::containing_address(0xdeadbeaa000),
                 PRESENT,
                 frame_allocator);
    mapping::map(&Page::containing_address(0xdeadbeab000),
                 PRESENT,
                 frame_allocator);
    mapping::map(&Page::containing_address(0xdeadbeac000),
                 PRESENT,
                 frame_allocator);
    mapping::map(&Page::containing_address(0xdeadbead000),
                 PRESENT,
                 frame_allocator);
    mapping::map(&Page::containing_address(0xcafebeaf000),
                 PRESENT,
                 frame_allocator);
    mapping::map(&Page::containing_address(0x0),
                 PRESENT,
                 frame_allocator);
}

pub const PAGE_SIZE: usize = 4096;
const ENTRY_COUNT: usize = 512;

pub type PhysicalAddress = usize;
pub type VirtualAddress = usize;

pub struct Page {
    number: usize,
}

impl Page {
    fn containing_address(address: VirtualAddress) -> Page {
        assert!(address < 0x0000_8000_0000_0000 || address >= 0xffff_8000_0000_0000,
            "invalid address: 0x{:x}", address);
        Page { number: address / PAGE_SIZE }
    }

    fn start_address(&self) -> VirtualAddress {
        self.number * PAGE_SIZE
    }

    fn p4_index(&self) -> usize {
        (self.number >> 27) & 0o777
    }
    fn p3_index(&self) -> usize {
        (self.number >> 18) & 0o777
    }
    fn p2_index(&self) -> usize {
        (self.number >> 9) & 0o777
    }
    fn p1_index(&self) -> usize {
        (self.number >> 0) & 0o777
    }
}
<|endoftext|>


<commit_before>use time_02::{OffsetDateTime, PrimitiveDateTime};
use tokio_postgres::types::{Date, Timestamp};

use crate::types::test_type;

#[tokio::test]
async fn test_naive_date_time_params() {
    fn make_check(time: &str) -> (Option<PrimitiveDateTime>, &str) {
        (
            Some(PrimitiveDateTime::parse(time, "'%Y-%m-%d %H:%M:%S.%f'").unwrap()),
            time,
        )
    }
    test_type(
        "TIMESTAMP",
        &[
            make_check("'1970-01-01 00:00:00.010000000'"),
            make_check("'1965-09-25 11:19:33.100314000'"),
            make_check("'2010-02-09 23:11:45.120200000'"),
            (None, "NULL"),
        ],
    )
    .await;
}

#[tokio::test]
async fn test_with_special_naive_date_time_params() {
    fn make_check(time: &str) -> (Timestamp<PrimitiveDateTime>, &str) {
        (
            Timestamp::Value(PrimitiveDateTime::parse(time, "'%Y-%m-%d %H:%M:%S.%f'").unwrap()),
            time,
        )
    }
    test_type(
        "TIMESTAMP",
        &[
            make_check("'1970-01-01 00:00:00.010000000'"),
            make_check("'1965-09-25 11:19:33.100314000'"),
            make_check("'2010-02-09 23:11:45.120200000'"),
            (Timestamp::PosInfinity, "'infinity'"),
            (Timestamp::NegInfinity, "'-infinity'"),
        ],
    )
    .await;
}

#[tokio::test]
async fn test_date_time_params() {
    fn make_check(time: &str) -> (Option<OffsetDateTime>, &str) {
        (
            Some(OffsetDateTime::parse(time, "'%Y-%m-%d %H:%M:%S.%f'").unwrap()),
            time,
        )
    }
    test_type(
        "TIMESTAMP WITH TIME ZONE",
        &[
            make_check("'1970-01-01 00:00:00.010000000'"),
            make_check("'1965-09-25 11:19:33.100314000'"),
            make_check("'2010-02-09 23:11:45.120200000'"),
            (None, "NULL"),
        ],
    )
    .await;
}

#[tokio::test]
async fn test_with_special_date_time_params() {
    fn make_check(time: &str) -> (Timestamp<OffsetDateTime>, &str) {
        (
            Timestamp::Value(OffsetDateTime::parse(time, "'%Y-%m-%d %H:%M:%S.%f'").unwrap()),
            time,
        )
    }
    test_type(
        "TIMESTAMP WITH TIME ZONE",
        &[
            make_check("'1970-01-01 00:00:00.010000000'"),
            make_check("'1965-09-25 11:19:33.100314000'"),
            make_check("'2010-02-09 23:11:45.120200000'"),
            (Timestamp::PosInfinity, "'infinity'"),
            (Timestamp::NegInfinity, "'-infinity'"),
        ],
    )
    .await;
}

#[tokio::test]
async fn test_date_params() {
    fn make_check(time: &str) -> (Option<time_02::Date>, &str) {
        (
            Some(time_02::Date::parse(time, "'%Y-%m-%d'").unwrap()),
            time,
        )
    }
    test_type(
        "DATE",
        &[
            make_check("'1970-01-01'"),
            make_check("'1965-09-25'"),
            make_check("'2010-02-09'"),
            (None, "NULL"),
        ],
    )
    .await;
}

#[tokio::test]
async fn test_with_special_date_params() {
    fn make_check(date: &str) -> (Date<time_02::Date>, &str) {
        (
            Date::Value(time_02::Date::parse(date, "'%Y-%m-%d'").unwrap()),
            date,
        )
    }
    test_type(
        "DATE",
        &[
            make_check("'1970-01-01'"),
            make_check("'1965-09-25'"),
            make_check("'2010-02-09'"),
            (Date::PosInfinity, "'infinity'"),
            (Date::NegInfinity, "'-infinity'"),
        ],
    )
    .await;
}

#[tokio::test]
async fn test_time_params() {
    fn make_check(time: &str) -> (Option<time_02::Time>, &str) {
        (
            Some(time_02::Time::parse(time, "'%H:%M:%S.%f'").unwrap()),
            time,
        )
    }
    test_type(
        "TIME",
        &[
            make_check("'00:00:00.010000000'"),
            make_check("'11:19:33.100314000'"),
            make_check("'23:11:45.120200000'"),
            (None, "NULL"),
        ],
    )
    .await;
}
<commit_msg>Remove fractional seconds from time_02 tests<commit_after>use time_02::{OffsetDateTime, PrimitiveDateTime};
use tokio_postgres::types::{Date, Timestamp};

use crate::types::test_type;

// time 0.2 does not [yet?] support parsing fractional seconds
// https://github.com/time-rs/time/issues/226

#[tokio::test]
async fn test_primitive_date_time_params() {
    fn make_check(time: &str) -> (Option<PrimitiveDateTime>, &str) {
        (
            Some(PrimitiveDateTime::parse(time, "'%Y-%m-%d %H:%M:%S'").unwrap()),
            time,
        )
    }
    test_type(
        "TIMESTAMP",
        &[
            make_check("'1970-01-01 00:00:00'"), // .010000000
            make_check("'1965-09-25 11:19:33'"), // .100314000
            make_check("'2010-02-09 23:11:45'"), // .120200000
            (None, "NULL"),
        ],
    )
    .await;
}

#[tokio::test]
async fn test_with_special_primitive_date_time_params() {
    fn make_check(time: &str) -> (Timestamp<PrimitiveDateTime>, &str) {
        (
            Timestamp::Value(PrimitiveDateTime::parse(time, "'%Y-%m-%d %H:%M:%S'").unwrap()),
            time,
        )
    }
    test_type(
        "TIMESTAMP",
        &[
            make_check("'1970-01-01 00:00:00'"), // .010000000
            make_check("'1965-09-25 11:19:33'"), // .100314000
            make_check("'2010-02-09 23:11:45'"), // .120200000
            (Timestamp::PosInfinity, "'infinity'"),
            (Timestamp::NegInfinity, "'-infinity'"),
        ],
    )
    .await;
}

#[tokio::test]
async fn test_offset_date_time_params() {
    fn make_check(time: &str) -> (Option<OffsetDateTime>, &str) {
        (
            Some(OffsetDateTime::parse(time, "'%Y-%m-%d %H:%M:%S %z'").unwrap()),
            time,
        )
    }
    test_type(
        "TIMESTAMP WITH TIME ZONE",
        &[
            make_check("'1970-01-01 00:00:00 +0000'"), // .010000000
            make_check("'1965-09-25 11:19:33 +0000'"), // .100314000
            make_check("'2010-02-09 23:11:45 +0000'"), // .120200000
            (None, "NULL"),
        ],
    )
    .await;
}

#[tokio::test]
async fn test_with_special_offset_date_time_params() {
    fn make_check(time: &str) -> (Timestamp<OffsetDateTime>, &str) {
        (
            Timestamp::Value(OffsetDateTime::parse(time, "'%Y-%m-%d %H:%M:%S %z'").unwrap()),
            time,
        )
    }
    test_type(
        "TIMESTAMP WITH TIME ZONE",
        &[
            make_check("'1970-01-01 00:00:00 +0000'"), // .010000000
            make_check("'1965-09-25 11:19:33 +0000'"), // .100314000
            make_check("'2010-02-09 23:11:45 +0000'"), // .120200000
            (Timestamp::PosInfinity, "'infinity'"),
            (Timestamp::NegInfinity, "'-infinity'"),
        ],
    )
    .await;
}

#[tokio::test]
async fn test_date_params() {
    fn make_check(time: &str) -> (Option<time_02::Date>, &str) {
        (
            Some(time_02::Date::parse(time, "'%Y-%m-%d'").unwrap()),
            time,
        )
    }
    test_type(
        "DATE",
        &[
            make_check("'1970-01-01'"),
            make_check("'1965-09-25'"),
            make_check("'2010-02-09'"),
            (None, "NULL"),
        ],
    )
    .await;
}

#[tokio::test]
async fn test_with_special_date_params() {
    fn make_check(date: &str) -> (Date<time_02::Date>, &str) {
        (
            Date::Value(time_02::Date::parse(date, "'%Y-%m-%d'").unwrap()),
            date,
        )
    }
    test_type(
        "DATE",
        &[
            make_check("'1970-01-01'"),
            make_check("'1965-09-25'"),
            make_check("'2010-02-09'"),
            (Date::PosInfinity, "'infinity'"),
            (Date::NegInfinity, "'-infinity'"),
        ],
    )
    .await;
}

#[tokio::test]
async fn test_time_params() {
    fn make_check(time: &str) -> (Option<time_02::Time>, &str) {
        (
            Some(time_02::Time::parse(time, "'%H:%M:%S'").unwrap()),
            time,
        )
    }
    test_type(
        "TIME",
        &[
            make_check("'00:00:00'"), // .010000000
            make_check("'11:19:33'"), // .100314000
            make_check("'23:11:45'"), // .120200000
            (None, "NULL"),
        ],
    )
    .await;
}
<|endoftext|>


<commit_before>//! Command queues.
//!
//! Queues are the execution paths of the graphical processing units. These process
//! submitted commands buffers.
//!
//! There are different types of queues, which can only handle associated command buffers.
//! `CommandQueue<B, C>` has the capability defined by `C`: graphics, compute and transfer.

pub mod capability;
pub mod family;

use std::iter;
use std::any::Any;
use std::borrow::Borrow;
use std::marker::PhantomData;

use command::{Primary, Submittable};
use error::HostExecutionError;
use pso;
use window::SwapImageIndex;
use Backend;

pub use self::capability::{
    Capability, Supports,
    Compute, Graphics, General, Transfer,
};
pub use self::family::{
    QueueFamily, QueueFamilyId, QueueGroup, Queues,
};

/// The type of the queue, an enum encompassing `queue::Capability`
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum QueueType {
    /// Supports all operations.
    General,
    /// Only supports graphics and transfer operations.
    Graphics,
    /// Only supports compute and transfer operations.
    Compute,
    /// Only supports transfer operations.
    Transfer,
}

/// Submission information for a command queue.
pub struct Submission<Ic, Iw, Is> {
    /// Command buffers to submit.
    pub command_buffers: Ic,
    /// Semaphores to wait being signalled before submission.
    pub wait_semaphores: Iw,
    /// Semaphores which get signalled after submission.
    pub signal_semaphores: Is,
}

/// `RawCommandQueue` are abstractions to the internal GPU execution engines.
/// Commands are executed on the the device by submitting command buffers to queues.
pub trait RawCommandQueue<B: Backend>: Any + Send + Sync {
    /// Submit command buffers to queue for execution.
    /// `fence` will be signalled after submission and _must_ be unsignalled.
    ///
    /// Unsafe because it's not checked that the queue can process the submitted command buffers.
    /// Trying to submit compute commands to a graphics queue will result in undefined behavior.
    /// Each queue implements safe wrappers according to their supported functionalities!
    unsafe fn submit<'a, T, Ic, S, Iw, Is>(
        &mut self, submission: Submission<Ic, Iw, Is>, fence: Option<&B::Fence>
    ) where
        T: 'a + Borrow<B::CommandBuffer>,
        Ic: IntoIterator<Item = &'a T>,
        S: 'a + Borrow<B::Semaphore>,
        Iw: IntoIterator<Item = (&'a S, pso::PipelineStage)>,
        Is: IntoIterator<Item = &'a S>;

    /// Presents the result of the queue to the given swapchains, after waiting on all the
    /// semaphores given in `wait_semaphores`. A given swapchain must not appear in this
    /// list more than once.
    ///
    /// Unsafe for the same reasons as `submit()`.
    unsafe fn present<'a, W, Is, S, Iw>(&mut self, swapchains: Is, wait_semaphores: Iw) -> Result<(), ()>
    where
        Self: Sized,
        W: 'a + Borrow<B::Swapchain>,
        Is: IntoIterator<Item = (&'a W, SwapImageIndex)>,
        S: 'a + Borrow<B::Semaphore>,
        Iw: IntoIterator<Item = &'a S>;

    /// Wait for the queue to idle.
    fn wait_idle(&self) -> Result<(), HostExecutionError>;
}

/// Stronger-typed and safer `CommandQueue` wraps around `RawCommandQueue`.
pub struct CommandQueue<B: Backend, C>(B::CommandQueue, PhantomData<C>);

impl<B: Backend, C: Capability> CommandQueue<B, C> {
    /// Create typed command queue from raw.
    ///
    /// # Safety
    ///
    /// `<C as Capability>::supported_by(queue_type)` must return true
    /// for `queue_type` being the type this `raw` queue.
    pub unsafe fn new(raw: B::CommandQueue) -> Self {
        CommandQueue(raw, PhantomData)
    }

    /// Get a reference to the raw command queue
    pub fn as_raw(&self) -> &B::CommandQueue {
        &self.0
    }

    /// Get a mutable reference to the raw command queue
    pub unsafe fn as_raw_mut(&mut self) -> &mut B::CommandQueue {
        &mut self.0
    }

    /// Downgrade a typed command queue to untyped one.
    pub fn into_raw(self) -> B::CommandQueue {
        self.0
    }

    /// Submits the submission command buffers to the queue for execution.
    /// `fence` will be signalled after submission and _must_ be unsignalled.
    pub unsafe fn submit<'a, T, Ic, S, Iw, Is>(&mut self,
        submission: Submission<Ic, Iw, Is>,
        fence: Option<&B::Fence>,
    ) where
        T: 'a + Submittable<B, C, Primary>,
        Ic: IntoIterator<Item = &'a T>,
        S: 'a + Borrow<B::Semaphore>,
        Iw: IntoIterator<Item = (&'a S, pso::PipelineStage)>,
        Is: IntoIterator<Item = &'a S>,
    {
        self.0.submit(submission, fence)
    }

    /// Submit command buffers without any semaphore waits or singals.
    pub unsafe fn submit_nosemaphores<'a, T, I>(
        &mut self, command_buffers: I, fence: Option<&B::Fence>
    ) where
        T: 'a + Submittable<B, C, Primary>,
        I: IntoIterator<Item = &'a T>
    {
        let submission = Submission {
            command_buffers,
            wait_semaphores: iter::empty(),
            signal_semaphores: iter::empty(),
        };
        self.submit::<_, _, B::Semaphore, _, _>(submission, fence)
    }

    /// Presents the result of the queue to the given swapchains, after waiting on all the
    /// semaphores given in `wait_semaphores`. A given swapchain must not appear in this
    /// list more than once.
    pub unsafe fn present<'a, W, Is, S, Iw>(&mut self, swapchains: Is, wait_semaphores: Iw) -> Result<(), ()>
    where
        W: 'a + Borrow<B::Swapchain>,
        Is: IntoIterator<Item = (&'a W, SwapImageIndex)>,
        S: 'a + Borrow<B::Semaphore>,
        Iw: IntoIterator<Item = &'a S>,
    {
        self.0.present(swapchains, wait_semaphores)
    }

    /// Wait for the queue to idle.
    pub fn wait_idle(&self) -> Result<(), HostExecutionError> {
        self.0.wait_idle()
    }

    /// Downgrade a command queue to a lesser capability type.
    pub unsafe fn downgrade<D>(&mut self) -> &mut CommandQueue<B, D>
    where
        C: Supports<D>,
    {
        ::std::mem::transmute(self)
    }
}
<commit_msg>Fix misleading documentation of `submit` functions<commit_after>//! Command queues.
//!
//! Queues are the execution paths of the graphical processing units. These process
//! submitted commands buffers.
//!
//! There are different types of queues, which can only handle associated command buffers.
//! `CommandQueue<B, C>` has the capability defined by `C`: graphics, compute and transfer.

pub mod capability;
pub mod family;

use std::iter;
use std::any::Any;
use std::borrow::Borrow;
use std::marker::PhantomData;

use command::{Primary, Submittable};
use error::HostExecutionError;
use pso;
use window::SwapImageIndex;
use Backend;

pub use self::capability::{
    Capability, Supports,
    Compute, Graphics, General, Transfer,
};
pub use self::family::{
    QueueFamily, QueueFamilyId, QueueGroup, Queues,
};

/// The type of the queue, an enum encompassing `queue::Capability`
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum QueueType {
    /// Supports all operations.
    General,
    /// Only supports graphics and transfer operations.
    Graphics,
    /// Only supports compute and transfer operations.
    Compute,
    /// Only supports transfer operations.
    Transfer,
}

/// Submission information for a command queue.
pub struct Submission<Ic, Iw, Is> {
    /// Command buffers to submit.
    pub command_buffers: Ic,
    /// Semaphores to wait being signalled before submission.
    pub wait_semaphores: Iw,
    /// Semaphores to signal after all command buffers in the submission have finished execution.
    pub signal_semaphores: Is,
}

/// `RawCommandQueue` are abstractions to the internal GPU execution engines.
/// Commands are executed on the the device by submitting command buffers to queues.
pub trait RawCommandQueue<B: Backend>: Any + Send + Sync {
    /// Submit command buffers to queue for execution.
    /// `fence` must be in unsignalled state, and will be signalled after all command buffers in the submission have
    /// finished execution.
    ///
    /// Unsafe because it's not checked that the queue can process the submitted command buffers.
    /// Trying to submit compute commands to a graphics queue will result in undefined behavior.
    /// Each queue implements safe wrappers according to their supported functionalities!
    unsafe fn submit<'a, T, Ic, S, Iw, Is>(
        &mut self, submission: Submission<Ic, Iw, Is>, fence: Option<&B::Fence>
    ) where
        T: 'a + Borrow<B::CommandBuffer>,
        Ic: IntoIterator<Item = &'a T>,
        S: 'a + Borrow<B::Semaphore>,
        Iw: IntoIterator<Item = (&'a S, pso::PipelineStage)>,
        Is: IntoIterator<Item = &'a S>;

    /// Presents the result of the queue to the given swapchains, after waiting on all the
    /// semaphores given in `wait_semaphores`. A given swapchain must not appear in this
    /// list more than once.
    ///
    /// Unsafe for the same reasons as `submit()`.
    unsafe fn present<'a, W, Is, S, Iw>(&mut self, swapchains: Is, wait_semaphores: Iw) -> Result<(), ()>
    where
        Self: Sized,
        W: 'a + Borrow<B::Swapchain>,
        Is: IntoIterator<Item = (&'a W, SwapImageIndex)>,
        S: 'a + Borrow<B::Semaphore>,
        Iw: IntoIterator<Item = &'a S>;

    /// Wait for the queue to idle.
    fn wait_idle(&self) -> Result<(), HostExecutionError>;
}

/// Stronger-typed and safer `CommandQueue` wraps around `RawCommandQueue`.
pub struct CommandQueue<B: Backend, C>(B::CommandQueue, PhantomData<C>);

impl<B: Backend, C: Capability> CommandQueue<B, C> {
    /// Create typed command queue from raw.
    ///
    /// # Safety
    ///
    /// `<C as Capability>::supported_by(queue_type)` must return true
    /// for `queue_type` being the type this `raw` queue.
    pub unsafe fn new(raw: B::CommandQueue) -> Self {
        CommandQueue(raw, PhantomData)
    }

    /// Get a reference to the raw command queue
    pub fn as_raw(&self) -> &B::CommandQueue {
        &self.0
    }

    /// Get a mutable reference to the raw command queue
    pub unsafe fn as_raw_mut(&mut self) -> &mut B::CommandQueue {
        &mut self.0
    }

    /// Downgrade a typed command queue to untyped one.
    pub fn into_raw(self) -> B::CommandQueue {
        self.0
    }

    /// Submit command buffers to queue for execution.
    /// `fence` must be in unsignalled state, and will be signalled after all command buffers in the submission have
    /// finished execution.
    pub unsafe fn submit<'a, T, Ic, S, Iw, Is>(&mut self,
        submission: Submission<Ic, Iw, Is>,
        fence: Option<&B::Fence>,
    ) where
        T: 'a + Submittable<B, C, Primary>,
        Ic: IntoIterator<Item = &'a T>,
        S: 'a + Borrow<B::Semaphore>,
        Iw: IntoIterator<Item = (&'a S, pso::PipelineStage)>,
        Is: IntoIterator<Item = &'a S>,
    {
        self.0.submit(submission, fence)
    }

    /// Submit command buffers without any semaphore waits or signals.
    pub unsafe fn submit_nosemaphores<'a, T, I>(
        &mut self, command_buffers: I, fence: Option<&B::Fence>
    ) where
        T: 'a + Submittable<B, C, Primary>,
        I: IntoIterator<Item = &'a T>
    {
        let submission = Submission {
            command_buffers,
            wait_semaphores: iter::empty(),
            signal_semaphores: iter::empty(),
        };
        self.submit::<_, _, B::Semaphore, _, _>(submission, fence)
    }

    /// Presents the result of the queue to the given swapchains, after waiting on all the
    /// semaphores given in `wait_semaphores`. A given swapchain must not appear in this
    /// list more than once.
    pub unsafe fn present<'a, W, Is, S, Iw>(&mut self, swapchains: Is, wait_semaphores: Iw) -> Result<(), ()>
    where
        W: 'a + Borrow<B::Swapchain>,
        Is: IntoIterator<Item = (&'a W, SwapImageIndex)>,
        S: 'a + Borrow<B::Semaphore>,
        Iw: IntoIterator<Item = &'a S>,
    {
        self.0.present(swapchains, wait_semaphores)
    }

    /// Wait for the queue to idle.
    pub fn wait_idle(&self) -> Result<(), HostExecutionError> {
        self.0.wait_idle()
    }

    /// Downgrade a command queue to a lesser capability type.
    pub unsafe fn downgrade<D>(&mut self) -> &mut CommandQueue<B, D>
    where
        C: Supports<D>,
    {
        ::std::mem::transmute(self)
    }
}
<|endoftext|>


<commit_before>use std::io::{self, Stdout, stdout, stdin};
use termion::{TermRead, IntoRawMode, RawTerminal};

use super::*;

/// The default for `Context.word_fn`.
pub fn get_buffer_words(buf: &Buffer) -> Vec<(usize, usize)> {
    let mut res = Vec::new();

    let mut word_start = None;
    let mut just_had_backslash = false;

    for (i, &c) in buf.chars().enumerate() {
        if c == '\\' {
            just_had_backslash = true;
            continue;
        }

        if let Some(start) = word_start {
            if c == ' ' && !just_had_backslash {
                res.push((start, i));
                word_start = None;
            }
        } else {
            if c != ' ' {
                word_start = Some(i);
            }
        }
    }

    if let Some(start) = word_start {
        res.push((start, buf.num_chars()));
    }

    res
}

pub struct Context {
    pub history: Vec<Buffer>,
    pub completer: Option<Box<Completer>>,
    pub word_fn: Box<Fn(&Buffer) -> Vec<(usize, usize)>>,
}

impl Context {
    pub fn new() -> Self {
        Context {
            history: vec![],
            completer: None,
            word_fn: Box::new(get_buffer_words),
        }
    }

    /// Creates an `Editor` and feeds it keypresses from stdin until the line is entered.
    /// The output is stdout.
    /// The returned line has the newline removed.
    /// Before returning, will revert all changes to the history buffers.
    pub fn read_line<P: Into<String>>(&mut self,
                                      prompt: P,
                                      mut handler: &mut EventHandler<RawTerminal<Stdout>>)
                                      -> io::Result<String> {
        let res = {
            let stdin = stdin();

            let stdout = stdout().into_raw_mode().unwrap();
            let mut ed = try!(Editor::new(stdout, prompt.into(), self));

            for c in stdin.keys() {
                if try!(ed.handle_key(c.unwrap(), handler)) {
                    break;
                }
            }

            Ok(ed.into())
        };

        self.revert_all_history();
        res
    }

    pub fn revert_all_history(&mut self) {
        for buf in &mut self.history {
            buf.revert();
        }
    }
}
<commit_msg>fix bug in get_buffer_words<commit_after>use std::io::{self, Stdout, stdout, stdin};
use termion::{TermRead, IntoRawMode, RawTerminal};

use super::*;

/// The default for `Context.word_fn`.
pub fn get_buffer_words(buf: &Buffer) -> Vec<(usize, usize)> {
    let mut res = Vec::new();

    let mut word_start = None;
    let mut just_had_backslash = false;

    for (i, &c) in buf.chars().enumerate() {
        if c == '\\' {
            just_had_backslash = true;
            continue;
        }

        if let Some(start) = word_start {
            if c == ' ' && !just_had_backslash {
                res.push((start, i));
                word_start = None;
            }
        } else {
            if c != ' ' {
                word_start = Some(i);
            }
        }

        just_had_backslash = false;
    }

    if let Some(start) = word_start {
        res.push((start, buf.num_chars()));
    }

    res
}

pub struct Context {
    pub history: Vec<Buffer>,
    pub completer: Option<Box<Completer>>,
    pub word_fn: Box<Fn(&Buffer) -> Vec<(usize, usize)>>,
}

impl Context {
    pub fn new() -> Self {
        Context {
            history: vec![],
            completer: None,
            word_fn: Box::new(get_buffer_words),
        }
    }

    /// Creates an `Editor` and feeds it keypresses from stdin until the line is entered.
    /// The output is stdout.
    /// The returned line has the newline removed.
    /// Before returning, will revert all changes to the history buffers.
    pub fn read_line<P: Into<String>>(&mut self,
                                      prompt: P,
                                      mut handler: &mut EventHandler<RawTerminal<Stdout>>)
                                      -> io::Result<String> {
        let res = {
            let stdin = stdin();

            let stdout = stdout().into_raw_mode().unwrap();
            let mut ed = try!(Editor::new(stdout, prompt.into(), self));

            for c in stdin.keys() {
                if try!(ed.handle_key(c.unwrap(), handler)) {
                    break;
                }
            }

            Ok(ed.into())
        };

        self.revert_all_history();
        res
    }

    pub fn revert_all_history(&mut self) {
        for buf in &mut self.history {
            buf.revert();
        }
    }
}
<|endoftext|>


<commit_before>//  Copyright (C) 2016 Sebastian Dröge <sebastian@centricular.com>
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Library General Public
//  License as published by the Free Software Foundation; either
//  version 2 of the License, or (at your option) any later version.
//
//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Library General Public License for more details.
//
//  You should have received a copy of the GNU Library General Public
//  License along with this library; if not, write to the
//  Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
//  Boston, MA 02110-1301, USA.

use libc::c_char;
use std::os::raw::c_void;
use std::ffi::CString;
use std::ffi::CStr;
use std::mem;
use std::borrow::Cow;
use std::fmt;

#[derive(Debug, PartialEq, Eq, Clone)]
pub enum Value<'a> {
    Bool(bool),
    Int(i32),
    String(Cow<'a, str>),
    Fraction(i32, i32),
}

pub struct Caps(*mut c_void);

#[repr(C)]
struct GValue {
    typ: usize,
    data: [u64; 2],
}

// See gtype.h
const TYPE_BOOLEAN: usize = (5 << 2);
const TYPE_INT: usize = (6 << 2);
const TYPE_STRING: usize = (16 << 2);

impl Caps {
    pub fn new_empty() -> Self {
        extern "C" {
            fn gst_caps_new_empty() -> *mut c_void;
        }

        let caps = Caps(unsafe { gst_caps_new_empty() });

        caps
    }

    pub fn new_any() -> Self {
        extern "C" {
            fn gst_caps_new_any() -> *mut c_void;
        }

        let caps = Caps(unsafe { gst_caps_new_any() });

        caps
    }

    pub fn new_simple(name: &str, values: Vec<(&str, &Value)>) -> Self {
        extern "C" {
            fn gst_caps_new_empty() -> *mut c_void;
            fn gst_caps_append_structure(caps: *mut c_void, structure: *mut c_void);
            fn gst_structure_new_empty(name: *const c_char) -> *mut c_void;
        }

        let mut caps = Caps(unsafe { gst_caps_new_empty() });

        let name_cstr = CString::new(name).unwrap();
        let structure = unsafe { gst_structure_new_empty(name_cstr.as_ptr()) };

        unsafe {
            gst_caps_append_structure(caps.0, structure);
        }

        caps.set_simple(values);

        caps
    }

    pub fn set_simple(&mut self, values: Vec<(&str, &Value)>) {
        extern "C" {
            fn gst_caps_set_value(caps: *mut c_void, name: *const c_char, value: *const GValue);
            fn g_value_init(value: *mut GValue, gtype: usize);
            fn g_value_unset(value: *mut GValue);
            fn g_value_set_boolean(value: *mut GValue, value: i32);
            fn g_value_set_int(value: *mut GValue, value: i32);
            fn g_value_set_string(value: *mut GValue, value: *const c_char);
            fn gst_value_set_fraction(value: *mut GValue, value_n: i32, value_d: i32);
            fn gst_fraction_get_type() -> usize;
        }

        for value in values {
            let name_cstr = CString::new(value.0).unwrap();
            let mut gvalue: GValue = unsafe { mem::zeroed() };

            match value.1 {
                &Value::Bool(v) => unsafe {
                    g_value_init(&mut gvalue as *mut GValue, TYPE_BOOLEAN);
                    g_value_set_boolean(&mut gvalue as *mut GValue, if v { 1 } else { 0 });
                    gst_caps_set_value(self.0, name_cstr.as_ptr(), &mut gvalue as *mut GValue);
                    g_value_unset(&mut gvalue as *mut GValue);
                },
                &Value::Int(v) => unsafe {
                    g_value_init(&mut gvalue as *mut GValue, TYPE_INT);
                    g_value_set_int(&mut gvalue as *mut GValue, v);
                    gst_caps_set_value(self.0, name_cstr.as_ptr(), &mut gvalue as *mut GValue);
                    g_value_unset(&mut gvalue as *mut GValue);
                },
                &Value::String(ref v) => unsafe {
                    let v_cstr = CString::new(String::from((*v).clone())).unwrap();

                    g_value_init(&mut gvalue as *mut GValue, TYPE_STRING);
                    g_value_set_string(&mut gvalue as *mut GValue, v_cstr.as_ptr());
                    gst_caps_set_value(self.0, name_cstr.as_ptr(), &mut gvalue as *mut GValue);
                    g_value_unset(&mut gvalue as *mut GValue);
                },
                &Value::Fraction(v_n, v_d) => unsafe {
                    g_value_init(&mut gvalue as *mut GValue, gst_fraction_get_type());
                    gst_value_set_fraction(&mut gvalue as *mut GValue, v_n, v_d);
                    gst_caps_set_value(self.0, name_cstr.as_ptr(), &mut gvalue as *mut GValue);
                    g_value_unset(&mut gvalue as *mut GValue);
                },
            }
        }
    }

    pub fn to_string(&self) -> String {
        extern "C" {
            fn gst_caps_to_string(caps: *mut c_void) -> *mut c_char;
        }

        unsafe { CStr::from_ptr(gst_caps_to_string(self.0)).to_string_lossy().into_owned() }
    }

    pub unsafe fn as_ptr(&self) -> *const c_void {
        self.0
    }

    pub fn make_writable(self: Caps) -> Caps {
        extern "C" {
            fn gst_mini_object_make_writable(obj: *mut c_void) -> *mut c_void;
        }

        let raw = unsafe { gst_mini_object_make_writable(self.0) };

        Caps(raw)
    }

    pub fn copy(&self) -> Caps {
        extern "C" {
            fn gst_mini_object_copy(obj: *const c_void) -> *mut c_void;
        }
        unsafe { Caps(gst_mini_object_copy(self.0)) }
    }
}

impl Clone for Caps {
    fn clone(&self) -> Self {
        extern "C" {
            fn gst_mini_object_ref(mini_object: *mut c_void) -> *mut c_void;
        }

        unsafe { Caps(gst_mini_object_ref(self.0)) }
    }
}

impl fmt::Debug for Caps {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str(&self.to_string())
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::ptr;
    use std::os::raw::c_void;

    fn init() {
        extern "C" {
            fn gst_init(argc: *mut c_void, argv: *mut c_void);
        }

        unsafe {
            gst_init(ptr::null_mut(), ptr::null_mut());
        }
    }

    #[test]
    fn test_simple() {
        init();

        let caps = Caps::new_simple("foo/bar",
                                    vec![("int", &Value::Int(12)),
                                         ("bool", &Value::Bool(true)),
                                         ("string", &Value::String("bla".into())),
                                         ("fraction", &Value::Fraction(1, 2))]);
        assert_eq!(caps.to_string(),
                   "foo/bar, int=(int)12, bool=(boolean)true, string=(string)bla, \
                    fraction=(fraction)1/2");
    }
}
<commit_msg>Add caps from string binding<commit_after>//  Copyright (C) 2016 Sebastian Dröge <sebastian@centricular.com>
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Library General Public
//  License as published by the Free Software Foundation; either
//  version 2 of the License, or (at your option) any later version.
//
//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Library General Public License for more details.
//
//  You should have received a copy of the GNU Library General Public
//  License along with this library; if not, write to the
//  Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
//  Boston, MA 02110-1301, USA.

use libc::c_char;
use std::os::raw::c_void;
use std::ffi::CString;
use std::ffi::CStr;
use std::mem;
use std::borrow::Cow;
use std::fmt;

#[derive(Debug, PartialEq, Eq, Clone)]
pub enum Value<'a> {
    Bool(bool),
    Int(i32),
    String(Cow<'a, str>),
    Fraction(i32, i32),
}

pub struct Caps(*mut c_void);

#[repr(C)]
struct GValue {
    typ: usize,
    data: [u64; 2],
}

// See gtype.h
const TYPE_BOOLEAN: usize = (5 << 2);
const TYPE_INT: usize = (6 << 2);
const TYPE_STRING: usize = (16 << 2);

impl Caps {
    pub fn new_empty() -> Self {
        extern "C" {
            fn gst_caps_new_empty() -> *mut c_void;
        }

        let caps = Caps(unsafe { gst_caps_new_empty() });

        caps
    }

    pub fn new_any() -> Self {
        extern "C" {
            fn gst_caps_new_any() -> *mut c_void;
        }

        let caps = Caps(unsafe { gst_caps_new_any() });

        caps
    }

    pub fn new_simple(name: &str, values: Vec<(&str, &Value)>) -> Self {
        extern "C" {
            fn gst_caps_new_empty() -> *mut c_void;
            fn gst_caps_append_structure(caps: *mut c_void, structure: *mut c_void);
            fn gst_structure_new_empty(name: *const c_char) -> *mut c_void;
        }

        let mut caps = Caps(unsafe { gst_caps_new_empty() });

        let name_cstr = CString::new(name).unwrap();
        let structure = unsafe { gst_structure_new_empty(name_cstr.as_ptr()) };

        unsafe {
            gst_caps_append_structure(caps.0, structure);
        }

        caps.set_simple(values);

        caps
    }

    pub fn from_string(value: &str) -> Option<Self> {
        extern "C" {
            fn gst_caps_from_string(value: *const c_char) -> *mut c_void;
        }

        let value_cstr = CString::new(value).unwrap();

        let caps_ptr = unsafe { gst_caps_from_string(value_cstr.as_ptr()) };

        if caps_ptr.is_null() {
            None
        } else {
            Some(Caps(caps_ptr))
        }
    }

    pub fn set_simple(&mut self, values: Vec<(&str, &Value)>) {
        extern "C" {
            fn gst_caps_set_value(caps: *mut c_void, name: *const c_char, value: *const GValue);
            fn g_value_init(value: *mut GValue, gtype: usize);
            fn g_value_unset(value: *mut GValue);
            fn g_value_set_boolean(value: *mut GValue, value: i32);
            fn g_value_set_int(value: *mut GValue, value: i32);
            fn g_value_set_string(value: *mut GValue, value: *const c_char);
            fn gst_value_set_fraction(value: *mut GValue, value_n: i32, value_d: i32);
            fn gst_fraction_get_type() -> usize;
        }

        for value in values {
            let name_cstr = CString::new(value.0).unwrap();
            let mut gvalue: GValue = unsafe { mem::zeroed() };

            match value.1 {
                &Value::Bool(v) => unsafe {
                    g_value_init(&mut gvalue as *mut GValue, TYPE_BOOLEAN);
                    g_value_set_boolean(&mut gvalue as *mut GValue, if v { 1 } else { 0 });
                    gst_caps_set_value(self.0, name_cstr.as_ptr(), &mut gvalue as *mut GValue);
                    g_value_unset(&mut gvalue as *mut GValue);
                },
                &Value::Int(v) => unsafe {
                    g_value_init(&mut gvalue as *mut GValue, TYPE_INT);
                    g_value_set_int(&mut gvalue as *mut GValue, v);
                    gst_caps_set_value(self.0, name_cstr.as_ptr(), &mut gvalue as *mut GValue);
                    g_value_unset(&mut gvalue as *mut GValue);
                },
                &Value::String(ref v) => unsafe {
                    let v_cstr = CString::new(String::from((*v).clone())).unwrap();

                    g_value_init(&mut gvalue as *mut GValue, TYPE_STRING);
                    g_value_set_string(&mut gvalue as *mut GValue, v_cstr.as_ptr());
                    gst_caps_set_value(self.0, name_cstr.as_ptr(), &mut gvalue as *mut GValue);
                    g_value_unset(&mut gvalue as *mut GValue);
                },
                &Value::Fraction(v_n, v_d) => unsafe {
                    g_value_init(&mut gvalue as *mut GValue, gst_fraction_get_type());
                    gst_value_set_fraction(&mut gvalue as *mut GValue, v_n, v_d);
                    gst_caps_set_value(self.0, name_cstr.as_ptr(), &mut gvalue as *mut GValue);
                    g_value_unset(&mut gvalue as *mut GValue);
                },
            }
        }
    }

    pub fn to_string(&self) -> String {
        extern "C" {
            fn gst_caps_to_string(caps: *mut c_void) -> *mut c_char;
        }

        unsafe { CStr::from_ptr(gst_caps_to_string(self.0)).to_string_lossy().into_owned() }
    }

    pub unsafe fn as_ptr(&self) -> *const c_void {
        self.0
    }

    pub fn make_writable(self: Caps) -> Caps {
        extern "C" {
            fn gst_mini_object_make_writable(obj: *mut c_void) -> *mut c_void;
        }

        let raw = unsafe { gst_mini_object_make_writable(self.0) };

        Caps(raw)
    }

    pub fn copy(&self) -> Caps {
        extern "C" {
            fn gst_mini_object_copy(obj: *const c_void) -> *mut c_void;
        }
        unsafe { Caps(gst_mini_object_copy(self.0)) }
    }
}

impl Clone for Caps {
    fn clone(&self) -> Self {
        extern "C" {
            fn gst_mini_object_ref(mini_object: *mut c_void) -> *mut c_void;
        }

        unsafe { Caps(gst_mini_object_ref(self.0)) }
    }
}

impl fmt::Debug for Caps {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str(&self.to_string())
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::ptr;
    use std::os::raw::c_void;

    fn init() {
        extern "C" {
            fn gst_init(argc: *mut c_void, argv: *mut c_void);
        }

        unsafe {
            gst_init(ptr::null_mut(), ptr::null_mut());
        }
    }

    #[test]
    fn test_simple() {
        init();

        let caps = Caps::new_simple("foo/bar",
                                    vec![("int", &Value::Int(12)),
                                         ("bool", &Value::Bool(true)),
                                         ("string", &Value::String("bla".into())),
                                         ("fraction", &Value::Fraction(1, 2))]);
        assert_eq!(caps.to_string(),
                   "foo/bar, int=(int)12, bool=(boolean)true, string=(string)bla, \
                    fraction=(fraction)1/2");
    }
}
<|endoftext|>


<commit_before>use std::fmt;

use byteorder::{ByteOrder, BigEndian};
use super::instruction::Instruction;
use super::mmu;
use super::machine_status::MachineStatus;
use super::super::memory;

const NUM_GPR: usize = 32;
const NUM_SPR: usize = 1023;
const NUM_SR : usize = 16;
const NUM_CR : usize = 8;

const XER : usize = 1;
const HID0: usize = 1008;

pub struct Cpu {
    pub memory: memory::Memory,
    pub mmu: mmu::Mmu,
    pub pc: u32,
    ctr: u32,
    gpr: [u32; NUM_GPR],
    spr: [u32; NUM_SPR],
    pub msr: MachineStatus,
    sr: [u32; NUM_SR],
    cr: [u8; NUM_CR],
    lr: u32
}

impl Cpu {
    pub fn new(memory: memory::Memory) -> Cpu {
        let msr = MachineStatus::default();

        // initial vector is (either 0x0000_0100 or 0xFFF0_0100) depending on MSR[IP]
        let pc = if msr.exception_prefix {
            0xFFF00100
        } else {
            0x00000100
        };

        Cpu {
            memory: memory,
            mmu: mmu::Mmu::new(),
            pc: pc,
            ctr: 0,
            gpr: [0; NUM_GPR],
            spr: [0; NUM_SPR],
            msr: msr,
            sr: [0; NUM_SR],
            cr: [0; NUM_CR],
            lr: 0
        }
    }

    pub fn run_instruction(&mut self) {
        let instr = self.read_instruction();

        println!("{:#x}:{:?}", instr.opcode(), self.gpr);

        match instr.opcode() {
            10 => self.cmpli(instr),
            14 => self.addi(instr),
            15 => self.addis(instr),
            16 => self.bcx(instr),
            18 => self.bx(instr),
            19 => {
                match instr.subopcode() {
                    150 => { // isync - instruction synchronize
                        // don't do anything
                    },
                    _ => panic!("Unrecognized instruction subopcode {} {}", instr.opcode(), instr.subopcode())
                }
            },
            21 => self.rlwinm(instr),
            24 => { // ori - OR immediate
                self.gpr[instr.a()] = self.gpr[instr.s()] | instr.uimm();
            },
            31 => {

                match instr.subopcode() {
                     28 => self.andx(instr),
                     40 => self.subf(instr),
                     83 => self.mfmsr(instr),
                    146 => self.mtmsr(instr),
                    210 => self.mtsr(instr),
                    339 => self.mfspr(instr),
                    371 => self.mftb(instr),
                    467 => self.mtspr(instr),
                    _   => panic!("Unrecognized instruction subopcode {} {}", instr.opcode(), instr.subopcode())
                }

            },
            32 => self.lwz(instr),
            36 => self.stw(instr),
            44 => self.sth(instr),
            _  => panic!("Unrecognized instruction {:#x} {:#b}", instr.0, instr.opcode())
        }

        self.pc += 4;
    }

    // FixMe: check if msr.exception_prefix (MSR[IP])
    fn read_instruction(&mut self) -> Instruction {
        let mut data = [0u8; 5];

        let addr = self.mmu.instr_address_translate(&self.msr, self.pc);

        self.memory.read(addr, &mut data);

        Instruction(BigEndian::read_u32(&data[0..]))
    }

    // complare logic immediate
    fn cmpli(&mut self, instr: Instruction) {
        let a = self.gpr[instr.a()];
        let b = instr.uimm();
        let mut c:u8;

        if a < b {
            c = 0b1000;
        } else if a > b {
            c = 0b0100;
        } else {
            c = 0b0010;
        }

        c |= self.spr[XER] as u8 & 0b1;

        self.cr[instr.crfd()] = c;
    }

    // add immediate
    fn addi(&mut self, instr: Instruction) {
        let a = instr.a();
        if a == 0 {
            self.gpr[instr.d()] = instr.uimm();
        } else {
            self.gpr[instr.d()] = self.gpr[a] + instr.uimm();
        }
    }

    // add immediate shifted
    fn addis(&mut self, instr: Instruction) {
        if instr.a() == 0 { // lis
            self.gpr[instr.d()] = instr.uimm() << 16;
        } else { // subis
            self.gpr[instr.d()] = self.gpr[instr.a()] + (instr.uimm() << 16);
        }
    }

    // ToDo: verify this is working
    fn bcx(&mut self, instr: Instruction) {
        let bo = instr.bo();

        let ctr_ok = if bon(bo, 2) == 0 {
            self.ctr.wrapping_sub(1); // FixMe: need wrapping :(

            if bon(bo, 3) != 0 {
                self.ctr == 0
            } else {
                self.ctr != 0
            }
        } else {
            true
        };

        let cond_ok = if bon(bo, 0) == 0 {
            (bon(bo, 1) == (self.cr[instr.bi()]))
        } else {
            true
        };

        if ctr_ok && cond_ok {
            if instr.aa() == 1 {
                self.pc = instr.bd() << 2;
            } else {
                self.pc = self.pc + (instr.bd() << 2);
            }

            if instr.lk() != 0 {
                self.lr = self.pc + 4;
            }
        }

    }

    // branch
    fn bx(&mut self, instr: Instruction) {
        if instr.aa() == 1 {
            self.pc = instr.li() << 2;
        } else {
            self.pc = self.pc + (instr.li() << 2);
        }

        if instr.lk() == 1 {
            self.lr = self.pc + 4;
        }
    }

    // rotate word immediate then AND with mask
    fn rlwinm(&mut self, instr: Instruction) {
        let r = self.gpr[instr.s()] << instr.sh();
        let m = mask(instr.mb(), instr.me());

        self.gpr[instr.a()] = r & m;
    }

    fn andx(&mut self, instr: Instruction) {
        self.gpr[instr.a()] = self.gpr[instr.d()] & self.gpr[instr.b()];

        // TODO: other registers altered
    }

    // subtract from
    fn subf(&mut self, instr: Instruction) {
        self.gpr[instr.d()] = self.gpr[instr.a()] + self.gpr[instr.b()] + 1;

        // TODO: other registers altered
    }

    // move from machine state register
    fn mfmsr(&mut self, instr: Instruction) {
        self.gpr[instr.d()] = self.msr.as_u32();

        // TODO: check privelege level
    }

    // move to machine state register
    fn mtmsr(&mut self, instr: Instruction) {
        self.msr = self.gpr[instr.s()].into();

        // TODO: check privelege level
    }

    // move to segment register
    fn mtsr(&mut self, instr: Instruction) {
        self.sr[instr.sr()] = self.gpr[instr.s()];

        // TODO: check privelege level -> supervisor level instruction
    }

    // move from special purpose register
    fn mfspr(&mut self, instr: Instruction) {
        let n = (instr.spr_upper() << 5) | (instr.spr_lower() & 0b1_1111);

        self.gpr[instr.s()] = self.spr[n as usize];

        // TODO: check privelege level
    }

    // move from time base
    fn mftb(&mut self, instr: Instruction) {
        let n = (instr.spr_upper() << 5) | (instr.spr_lower() & 0b1_1111);

        match n {
            268 => { // TBL
                println!("FIXME: mftb, get time base tbl");
            },
            269 => { // TBR
                println!("FIXME: mftb, get time base tbu");
            },
            _ => panic!("Unrecognized TBR {}", n) // FixMe: invoke error handler
        }
    }

    // move special purpose register
    fn mtspr(&mut self, instr: Instruction) {
        let n = ((instr.spr_upper() << 5) | (instr.spr_lower() & 0b1_1111)) as usize;

        match n {
            528 ... 543 => { // if IBAT or DBAT, write to MMU register
                self.mmu.write_bat_reg(n, self.gpr[instr.s()]);
                //panic!("FixMe: write to BAT registers");
            },
            _ => self.spr[n] = self.gpr[instr.s()]
        }

        // TODO: check privelege level
    }

    // load word and zero
    fn lwz(&mut self, instr: Instruction) {
        let ea = if instr.a() == 0 {
            instr.simm()
        } else {
            self.gpr[instr.a()] + instr.simm()
        };

        let addr = self.mmu.data_address_translate(&self.msr, ea);

        self.gpr[instr.d()] = self.memory.read_u32(addr);
    }

    // store word
    fn stw(&mut self, instr: Instruction) {
        let ea = if instr.a() == 0 {
            instr.simm()
        } else {
            self.gpr[instr.a()] + instr.simm()
        };

        let addr = self.mmu.data_address_translate(&self.msr, ea);

        self.memory.write_u32(addr, self.gpr[instr.s()]);
    }

    // store half word
    fn sth(&mut self, instr: Instruction) {
        let ea = if instr.a() == 0 {
            instr.simm()
        } else {
            self.gpr[instr.a()] + instr.simm()
        };

        let addr = self.mmu.data_address_translate(&self.msr, ea);

        self.memory.write_u16(addr, self.gpr[instr.s()] as u16);
    }
}

//((1 << (x - y +1)) - 1) << y
// FixMe: not sure if this is correct
// actually I think this might be backwards
fn mask(x: u8, y: u8) -> u32 {
    let mut mask:u32 = 0xFFFFFFFF >> y;

    if x >= 31 {
        mask ^= 0;
    } else {
        mask ^= 0xFFFFFFFF >> (x + 1);
    }

    if y > x {
        !mask
    } else {
        mask
    }
}

fn bon(bo: u8, n: u8) -> u8 {
    (bo >> (4-n)) & 1
}

impl fmt::Debug for Cpu {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "MSR: {:?} gpr: {:?}, sr: {:?}, cr:{:?}, HID0: {}", self.msr, self.gpr, self.sr, self.cr, self.spr[HID0])
    }
}
<commit_msg>updated mtspr<commit_after>use std::fmt;

use byteorder::{ByteOrder, BigEndian};
use super::instruction::Instruction;
use super::mmu;
use super::machine_status::MachineStatus;
use super::super::memory;

const NUM_GPR: usize = 32;
const NUM_SPR: usize = 1023;
const NUM_SR : usize = 16;
const NUM_CR : usize = 8;

const XER : usize = 1;
const HID0: usize = 1008;

pub struct Cpu {
    pub memory: memory::Memory,
    pub mmu: mmu::Mmu,
    pub pc: u32,
    ctr: u32,
    gpr: [u32; NUM_GPR],
    spr: [u32; NUM_SPR], // ToDo phase out
    pub msr: MachineStatus,
    sr: [u32; NUM_SR],
    cr: [u8; NUM_CR],
    lr: u32
}

impl Cpu {
    pub fn new(memory: memory::Memory) -> Cpu {
        let msr = MachineStatus::default();

        // initial vector is (either 0x0000_0100 or 0xFFF0_0100) depending on MSR[IP]
        let pc = if msr.exception_prefix {
            0xFFF00100
        } else {
            0x00000100
        };

        Cpu {
            memory: memory,
            mmu: mmu::Mmu::new(),
            pc: pc,
            ctr: 0,
            gpr: [0; NUM_GPR],
            spr: [0; NUM_SPR],
            msr: msr,
            sr: [0; NUM_SR],
            cr: [0; NUM_CR],
            lr: 0
        }
    }

    pub fn run_instruction(&mut self) {
        let instr = self.read_instruction();

        println!("{:#x}:{:?}", instr.opcode(), self.gpr);

        match instr.opcode() {
            10 => self.cmpli(instr),
            14 => self.addi(instr),
            15 => self.addis(instr),
            16 => self.bcx(instr),
            18 => self.bx(instr),
            19 => {
                match instr.subopcode() {
                    150 => { // isync - instruction synchronize
                        // don't do anything
                    },
                    _ => panic!("Unrecognized instruction subopcode {} {}", instr.opcode(), instr.subopcode())
                }
            },
            21 => self.rlwinm(instr),
            24 => { // ori - OR immediate
                self.gpr[instr.a()] = self.gpr[instr.s()] | instr.uimm();
            },
            31 => {

                match instr.subopcode() {
                     28 => self.andx(instr),
                     40 => self.subf(instr),
                     83 => self.mfmsr(instr),
                    146 => self.mtmsr(instr),
                    210 => self.mtsr(instr),
                    339 => self.mfspr(instr),
                    371 => self.mftb(instr),
                    467 => self.mtspr(instr),
                    _   => panic!("Unrecognized instruction subopcode {} {}", instr.opcode(), instr.subopcode())
                }

            },
            32 => self.lwz(instr),
            36 => self.stw(instr),
            44 => self.sth(instr),
            _  => panic!("Unrecognized instruction {:#x} {:#b}", instr.0, instr.opcode())
        }

        self.pc += 4;
    }

    // FixMe: check if msr.exception_prefix (MSR[IP])
    fn read_instruction(&mut self) -> Instruction {
        let mut data = [0u8; 5];

        let addr = self.mmu.instr_address_translate(&self.msr, self.pc);

        self.memory.read(addr, &mut data);

        Instruction(BigEndian::read_u32(&data[0..]))
    }

    // complare logic immediate
    fn cmpli(&mut self, instr: Instruction) {
        let a = self.gpr[instr.a()];
        let b = instr.uimm();
        let mut c:u8;

        if a < b {
            c = 0b1000;
        } else if a > b {
            c = 0b0100;
        } else {
            c = 0b0010;
        }

        c |= self.spr[XER] as u8 & 0b1;

        self.cr[instr.crfd()] = c;
    }

    // add immediate
    fn addi(&mut self, instr: Instruction) {
        let a = instr.a();
        if a == 0 {
            self.gpr[instr.d()] = instr.uimm();
        } else {
            self.gpr[instr.d()] = self.gpr[a] + instr.uimm();
        }
    }

    // add immediate shifted
    fn addis(&mut self, instr: Instruction) {
        if instr.a() == 0 { // lis
            self.gpr[instr.d()] = instr.uimm() << 16;
        } else { // subis
            self.gpr[instr.d()] = self.gpr[instr.a()] + (instr.uimm() << 16);
        }
    }

    // ToDo: verify this is working
    fn bcx(&mut self, instr: Instruction) {
        let bo = instr.bo();

        let ctr_ok = if bon(bo, 2) == 0 {
            self.ctr.wrapping_sub(1); // FixMe: need wrapping :(

            if bon(bo, 3) != 0 {
                self.ctr == 0
            } else {
                self.ctr != 0
            }
        } else {
            true
        };

        let cond_ok = if bon(bo, 0) == 0 {
            (bon(bo, 1) == (self.cr[instr.bi()]))
        } else {
            true
        };

        if ctr_ok && cond_ok {
            if instr.aa() == 1 {
                self.pc = instr.bd() << 2;
            } else {
                self.pc = self.pc + (instr.bd() << 2);
            }

            if instr.lk() != 0 {
                self.lr = self.pc + 4;
            }
        }

    }

    // branch
    fn bx(&mut self, instr: Instruction) {
        if instr.aa() == 1 {
            self.pc = instr.li() << 2;
        } else {
            self.pc = self.pc + (instr.li() << 2);
        }

        if instr.lk() == 1 {
            self.lr = self.pc + 4;
        }
    }

    // rotate word immediate then AND with mask
    fn rlwinm(&mut self, instr: Instruction) {
        let r = self.gpr[instr.s()] << instr.sh();
        let m = mask(instr.mb(), instr.me());

        self.gpr[instr.a()] = r & m;
    }

    fn andx(&mut self, instr: Instruction) {
        self.gpr[instr.a()] = self.gpr[instr.d()] & self.gpr[instr.b()];

        // TODO: other registers altered
    }

    // subtract from
    fn subf(&mut self, instr: Instruction) {
        self.gpr[instr.d()] = self.gpr[instr.a()] + self.gpr[instr.b()] + 1;

        // TODO: other registers altered
    }

    // move from machine state register
    fn mfmsr(&mut self, instr: Instruction) {
        self.gpr[instr.d()] = self.msr.as_u32();

        // TODO: check privelege level
    }

    // move to machine state register
    fn mtmsr(&mut self, instr: Instruction) {
        self.msr = self.gpr[instr.s()].into();

        // TODO: check privelege level
    }

    // move to segment register
    fn mtsr(&mut self, instr: Instruction) {
        self.sr[instr.sr()] = self.gpr[instr.s()];

        // TODO: check privelege level -> supervisor level instruction
    }

    // move from special purpose register
    fn mfspr(&mut self, instr: Instruction) {
        let n = (instr.spr_upper() << 5) | (instr.spr_lower() & 0b1_1111);

        self.gpr[instr.s()] = self.spr[n as usize];

        // TODO: check privelege level
    }

    // move from time base
    fn mftb(&mut self, instr: Instruction) {
        let n = (instr.spr_upper() << 5) | (instr.spr_lower() & 0b1_1111);

        match n {
            268 => { // TBL
                println!("FIXME: mftb, get time base tbl");
            },
            269 => { // TBR
                println!("FIXME: mftb, get time base tbu");
            },
            _ => panic!("Unrecognized TBR {}", n) // FixMe: invoke error handler
        }
    }

    // move special purpose register
    fn mtspr(&mut self, instr: Instruction) {
        let n = ((instr.spr_upper() << 5) | (instr.spr_lower() & 0b1_1111)) as usize;

        match n {
            8 => self.lr = self.gpr[instr.s()],
            9 => self.ctr = self.gpr[instr.s()],
            528 ... 543 => { // if IBAT or DBAT, write to MMU register
                self.mmu.write_bat_reg(n, self.gpr[instr.s()]);
                //panic!("FixMe: write to BAT registers");
            },
            _ => self.spr[n] = self.gpr[instr.s()]
        }

        // TODO: check privelege level
    }

    // load word and zero
    fn lwz(&mut self, instr: Instruction) {
        let ea = if instr.a() == 0 {
            instr.simm()
        } else {
            self.gpr[instr.a()] + instr.simm()
        };

        let addr = self.mmu.data_address_translate(&self.msr, ea);

        self.gpr[instr.d()] = self.memory.read_u32(addr);
    }

    // store word
    fn stw(&mut self, instr: Instruction) {
        let ea = if instr.a() == 0 {
            instr.simm()
        } else {
            self.gpr[instr.a()] + instr.simm()
        };

        let addr = self.mmu.data_address_translate(&self.msr, ea);

        self.memory.write_u32(addr, self.gpr[instr.s()]);
    }

    // store half word
    fn sth(&mut self, instr: Instruction) {
        let ea = if instr.a() == 0 {
            instr.simm()
        } else {
            self.gpr[instr.a()] + instr.simm()
        };

        let addr = self.mmu.data_address_translate(&self.msr, ea);

        self.memory.write_u16(addr, self.gpr[instr.s()] as u16);
    }
}

//((1 << (x - y +1)) - 1) << y
// FixMe: not sure if this is correct
// actually I think this might be backwards
fn mask(x: u8, y: u8) -> u32 {
    let mut mask:u32 = 0xFFFFFFFF >> y;

    if x >= 31 {
        mask ^= 0;
    } else {
        mask ^= 0xFFFFFFFF >> (x + 1);
    }

    if y > x {
        !mask
    } else {
        mask
    }
}

fn bon(bo: u8, n: u8) -> u8 {
    (bo >> (4-n)) & 1
}

impl fmt::Debug for Cpu {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "MSR: {:?} gpr: {:?}, sr: {:?}, cr:{:?}, HID0: {}", self.msr, self.gpr, self.sr, self.cr, self.spr[HID0])
    }
}
<|endoftext|>


<commit_before>use beacon_chain::{BeaconChain, BeaconChainTypes};
use environment::RuntimeContext;
use exit_future::Signal;
use futures::{Future, Stream};
use network::Service as NetworkService;
use parking_lot::Mutex;
use slog::{debug, error, info, warn};
use slot_clock::SlotClock;
use std::sync::Arc;
use std::time::{Duration, Instant};
use tokio::timer::Interval;
use types::{EthSpec, Slot};

/// Create a warning log whenever the peer count is at or below this value.
pub const WARN_PEER_COUNT: usize = 1;

const SECS_PER_MINUTE: u64 = 60;
const SECS_PER_HOUR: u64 = 3600;
const SECS_PER_DAY: u64 = 86400; // non-leap
const SECS_PER_WEEK: u64 = 604800; // non-leap
const DAYS_PER_WEEK: u64 = 7;
const HOURS_PER_DAY: u64 = 24;
const MINUTES_PER_HOUR: u64 = 60;

/// Spawns a notifier service which periodically logs information about the node.
pub fn spawn_notifier<T: BeaconChainTypes>(
    context: RuntimeContext<T::EthSpec>,
    beacon_chain: Arc<BeaconChain<T>>,
    network: Arc<NetworkService<T>>,
    milliseconds_per_slot: u64,
) -> Result<Signal, String> {
    let log_1 = context.log.clone();
    let log_2 = context.log.clone();

    let slot_duration = Duration::from_millis(milliseconds_per_slot);
    let duration_to_next_slot = beacon_chain
        .slot_clock
        .duration_to_next_slot()
        .ok_or_else(|| "slot_notifier unable to determine time to next slot")?;

    // Run this half way through each slot.
    let start_instant = Instant::now() + duration_to_next_slot + (slot_duration / 2);

    // Run this each slot.
    let interval_duration = slot_duration;

    let previous_head_slot = Mutex::new(Slot::new(0));

    let interval_future = Interval::new(start_instant, interval_duration)
        .map_err(
            move |e| error!(log_1, "Slot notifier timer failed"; "error" => format!("{:?}", e)),
        )
        .for_each(move |_| {
            let log = log_2.clone();

            let connected_peer_count = network.libp2p_service().lock().swarm.connected_peers();

            let head = beacon_chain.head();

            let head_slot = head.beacon_block.slot;
            let head_epoch = head_slot.epoch(T::EthSpec::slots_per_epoch());
            let current_slot = beacon_chain.slot().map_err(|e| {
                error!(
                    log,
                    "Unable to read current slot";
                    "error" => format!("{:?}", e)
                )
            })?;
            let current_epoch = current_slot.epoch(T::EthSpec::slots_per_epoch());
            let finalized_epoch = head.beacon_state.finalized_checkpoint.epoch;
            let finalized_root = head.beacon_state.finalized_checkpoint.root;
            let head_root = head.beacon_block_root;

            let mut previous_head_slot = previous_head_slot.lock();

            // The next two lines take advantage of saturating subtraction on `Slot`.
            let head_distance = current_slot - head_slot;
            let slots_since_last_update = head_slot - *previous_head_slot;

            *previous_head_slot = head_slot;

            if connected_peer_count <= WARN_PEER_COUNT {
                warn!(log, "Low peer count"; "peer_count" => connected_peer_count);
            }

            debug!(
                log,
                "Slot timer";
                "peers" => connected_peer_count,
                "finalized_root" => format!("{}", finalized_root),
                "finalized_epoch" => finalized_epoch,
                "head_block" => format!("{}", head_root),
                "head_slot" => head_slot,
                "current_slot" => current_slot,
            );

            if head_epoch + 1 < current_epoch {
                let distance = format!(
                    "{} slots ({})",
                    head_distance.as_u64(),
                    slot_distance_pretty(head_distance, slot_duration)
                );

                info!(
                    log,
                    "Syncing";
                    "peers" => connected_peer_count,
                    "speed" => sync_rate_pretty(slots_since_last_update, interval_duration.as_secs()),
                    "distance" => distance
                );

                return Ok(());
            };

            macro_rules! not_quite_synced_log {
                ($message: expr) => {
                    info!(
                        log_2,
                        $message;
                        "peers" => connected_peer_count,
                        "finalized_root" => format!("{}", finalized_root),
                        "finalized_epoch" => finalized_epoch,
                        "head_slot" => head_slot,
                        "current_slot" => current_slot,
                    );
                }
            }

            if head_epoch + 1 == current_epoch {
                not_quite_synced_log!("Synced to previous epoch")
            } else if head_slot != current_slot {
                not_quite_synced_log!("Synced to current epoch")
            } else {
                info!(
                    log_2,
                    "Synced";
                    "peers" => connected_peer_count,
                    "finalized_root" => format!("{}", finalized_root),
                    "finalized_epoch" => finalized_epoch,
                    "epoch" => current_epoch,
                    "slot" => current_slot,
                );
            };

            Ok(())
        });

    let (exit_signal, exit) = exit_future::signal();
    context
        .executor
        .spawn(exit.until(interval_future).map(|_| ()));

    Ok(exit_signal)
}

/// Returns a nicely formated string describing the rate of slot imports per second.
fn sync_rate_pretty(slots_since_last_update: Slot, update_interval_secs: u64) -> String {
    if update_interval_secs == 0 {
        return "Error".into();
    }

    if slots_since_last_update == 0 {
        "No progress".into()
    } else {
        format!(
            "{} slots/sec",
            slots_since_last_update / update_interval_secs
        )
    }
}

/// Returns a nicely formatted string describing the `slot_span` in terms of weeks, days, hours
/// and/or minutes.
fn slot_distance_pretty(slot_span: Slot, slot_duration: Duration) -> String {
    if slot_duration == Duration::from_secs(0) {
        return String::from("Unknown");
    }

    let secs = (slot_duration * slot_span.as_u64() as u32).as_secs();

    let weeks = secs / SECS_PER_WEEK;
    let days = secs / SECS_PER_DAY;
    let hours = secs / SECS_PER_HOUR;
    let minutes = secs / SECS_PER_MINUTE;

    if weeks > 0 {
        format!("{} weeks {} days", weeks, days % DAYS_PER_WEEK)
    } else if days > 0 {
        format!("{} days {} hrs", days, hours % HOURS_PER_DAY)
    } else if hours > 0 {
        format!("{} hrs {} mins", hours, minutes % MINUTES_PER_HOUR)
    } else {
        format!("{} mins", minutes)
    }
}
<commit_msg>Add decimals display to notifier sync speed (#678)<commit_after>use beacon_chain::{BeaconChain, BeaconChainTypes};
use environment::RuntimeContext;
use exit_future::Signal;
use futures::{Future, Stream};
use network::Service as NetworkService;
use parking_lot::Mutex;
use slog::{debug, error, info, warn};
use slot_clock::SlotClock;
use std::sync::Arc;
use std::time::{Duration, Instant};
use tokio::timer::Interval;
use types::{EthSpec, Slot};

/// Create a warning log whenever the peer count is at or below this value.
pub const WARN_PEER_COUNT: usize = 1;

const SECS_PER_MINUTE: u64 = 60;
const SECS_PER_HOUR: u64 = 3600;
const SECS_PER_DAY: u64 = 86400; // non-leap
const SECS_PER_WEEK: u64 = 604800; // non-leap
const DAYS_PER_WEEK: u64 = 7;
const HOURS_PER_DAY: u64 = 24;
const MINUTES_PER_HOUR: u64 = 60;

/// Spawns a notifier service which periodically logs information about the node.
pub fn spawn_notifier<T: BeaconChainTypes>(
    context: RuntimeContext<T::EthSpec>,
    beacon_chain: Arc<BeaconChain<T>>,
    network: Arc<NetworkService<T>>,
    milliseconds_per_slot: u64,
) -> Result<Signal, String> {
    let log_1 = context.log.clone();
    let log_2 = context.log.clone();

    let slot_duration = Duration::from_millis(milliseconds_per_slot);
    let duration_to_next_slot = beacon_chain
        .slot_clock
        .duration_to_next_slot()
        .ok_or_else(|| "slot_notifier unable to determine time to next slot")?;

    // Run this half way through each slot.
    let start_instant = Instant::now() + duration_to_next_slot + (slot_duration / 2);

    // Run this each slot.
    let interval_duration = slot_duration;

    let previous_head_slot = Mutex::new(Slot::new(0));

    let interval_future = Interval::new(start_instant, interval_duration)
        .map_err(
            move |e| error!(log_1, "Slot notifier timer failed"; "error" => format!("{:?}", e)),
        )
        .for_each(move |_| {
            let log = log_2.clone();

            let connected_peer_count = network.libp2p_service().lock().swarm.connected_peers();

            let head = beacon_chain.head();

            let head_slot = head.beacon_block.slot;
            let head_epoch = head_slot.epoch(T::EthSpec::slots_per_epoch());
            let current_slot = beacon_chain.slot().map_err(|e| {
                error!(
                    log,
                    "Unable to read current slot";
                    "error" => format!("{:?}", e)
                )
            })?;
            let current_epoch = current_slot.epoch(T::EthSpec::slots_per_epoch());
            let finalized_epoch = head.beacon_state.finalized_checkpoint.epoch;
            let finalized_root = head.beacon_state.finalized_checkpoint.root;
            let head_root = head.beacon_block_root;

            let mut previous_head_slot = previous_head_slot.lock();

            // The next two lines take advantage of saturating subtraction on `Slot`.
            let head_distance = current_slot - head_slot;
            let slots_since_last_update = head_slot - *previous_head_slot;

            *previous_head_slot = head_slot;

            if connected_peer_count <= WARN_PEER_COUNT {
                warn!(log, "Low peer count"; "peer_count" => connected_peer_count);
            }

            debug!(
                log,
                "Slot timer";
                "peers" => connected_peer_count,
                "finalized_root" => format!("{}", finalized_root),
                "finalized_epoch" => finalized_epoch,
                "head_block" => format!("{}", head_root),
                "head_slot" => head_slot,
                "current_slot" => current_slot,
            );

            if head_epoch + 1 < current_epoch {
                let distance = format!(
                    "{} slots ({})",
                    head_distance.as_u64(),
                    slot_distance_pretty(head_distance, slot_duration)
                );

                info!(
                    log,
                    "Syncing";
                    "peers" => connected_peer_count,
                    "speed" => sync_rate_pretty(slots_since_last_update, interval_duration.as_secs()),
                    "distance" => distance
                );

                return Ok(());
            };

            macro_rules! not_quite_synced_log {
                ($message: expr) => {
                    info!(
                        log_2,
                        $message;
                        "peers" => connected_peer_count,
                        "finalized_root" => format!("{}", finalized_root),
                        "finalized_epoch" => finalized_epoch,
                        "head_slot" => head_slot,
                        "current_slot" => current_slot,
                    );
                }
            }

            if head_epoch + 1 == current_epoch {
                not_quite_synced_log!("Synced to previous epoch")
            } else if head_slot != current_slot {
                not_quite_synced_log!("Synced to current epoch")
            } else {
                info!(
                    log_2,
                    "Synced";
                    "peers" => connected_peer_count,
                    "finalized_root" => format!("{}", finalized_root),
                    "finalized_epoch" => finalized_epoch,
                    "epoch" => current_epoch,
                    "slot" => current_slot,
                );
            };

            Ok(())
        });

    let (exit_signal, exit) = exit_future::signal();
    context
        .executor
        .spawn(exit.until(interval_future).map(|_| ()));

    Ok(exit_signal)
}

/// Returns a nicely formated string describing the rate of slot imports per second.
fn sync_rate_pretty(slots_since_last_update: Slot, update_interval_secs: u64) -> String {
    if update_interval_secs == 0 {
        return "Error".into();
    }

    if slots_since_last_update == 0 {
        "No progress".into()
    } else {
        let distance = f64::from(slots_since_last_update.as_u64() as u32);
        let time = f64::from(update_interval_secs as u32);

        format!("{:.2} slots/sec", distance / time)
    }
}

/// Returns a nicely formatted string describing the `slot_span` in terms of weeks, days, hours
/// and/or minutes.
fn slot_distance_pretty(slot_span: Slot, slot_duration: Duration) -> String {
    if slot_duration == Duration::from_secs(0) {
        return String::from("Unknown");
    }

    let secs = (slot_duration * slot_span.as_u64() as u32).as_secs();

    let weeks = secs / SECS_PER_WEEK;
    let days = secs / SECS_PER_DAY;
    let hours = secs / SECS_PER_HOUR;
    let minutes = secs / SECS_PER_MINUTE;

    if weeks > 0 {
        format!("{} weeks {} days", weeks, days % DAYS_PER_WEEK)
    } else if days > 0 {
        format!("{} days {} hrs", days, hours % HOURS_PER_DAY)
    } else if hours > 0 {
        format!("{} hrs {} mins", hours, minutes % MINUTES_PER_HOUR)
    } else {
        format!("{} mins", minutes)
    }
}
<|endoftext|>


<commit_before>extern crate "parser-combinators" as parser_combinators;
use self::parser_combinators::{between, spaces, many1, sep_by, satisfy, Parser, ParserExt, ParseResult};
use self::parser_combinators::primitives::{State, Stream};
use ast;

fn expr<I>(input: State<I>) -> ParseResult(ast::ExprNode, I)
    where I: Stream<Item=char> {
        unimplemented!()
}

#[cfg(test)]
mod tests {

    #[test]
    fn test_basic_ident() {
        assert_eq!(
            (expr as fn (_) -> _).parse("ident"),
            Ok((ast::NameNode { name: "ident" }, ""))
            );
    }

}<commit_msg>Fix tests for parser panicking<commit_after>extern crate "parser-combinators" as parser_combinators;
use self::parser_combinators::{between, spaces, many1, sep_by, satisfy, Parser, ParserExt, ParseResult};
use self::parser_combinators::primitives::{State, Stream};
use super::ast;

pub fn expr<I>(input: State<I>) -> ParseResult(ast::ExprNode, I)
    where I: Stream<Item=char> {
        unimplemented!()
}

#[cfg(test)]
mod tests {
    use ::ast;
    use super::expr;
    #[test]
    fn test_basic_ident() {
        assert_eq!(
            (expr as fn (_) -> _).parse("ident"),
            Ok((ast::NameNode { name: "ident" }, ""))
            );
    }

}<|endoftext|>