<commit_before>use std::collections::HashMap;
use std::io::File;

use error::{
    Error, ImapResult, InternalIoError, MessageDecodeError
};

#[deriving(Show)]
enum Flag {
    Answered,
    Draft,
    Flagged,
    Seen
}

#[deriving(Show)]
pub struct Message {
    uid: u32,
    pub path: String,
    headers: HashMap<String, String>,
    body: Vec<MIMEPart>,
    flags: Vec<Flag>,
    pub deleted: bool,
    raw_contents: String
}

#[deriving(Show)]
pub struct MIMEPart {
    mime_header: String,
    mime_body: String
}

impl Message {
    pub fn parse(arg_path: &Path) -> ImapResult<Message> {
        // Load the file contents.
        let file = match File::open(arg_path) {
            Ok(mut file) => match file.read_to_end() {
                Ok(contents) => contents,
                Err(e) => return Err(Error::simple(InternalIoError(e), "Failed to read mail file."))
            },
            Err(e) => return Err(Error::simple(InternalIoError(e), "Failed to open mail file."))
        };
        let raw_contents = String::from_utf8_lossy(file.as_slice()).to_string();

        let mut path = arg_path.filename_str().unwrap().splitn(1, ':');
        let filename = path.next().unwrap();
        let flags = path.next().unwrap();

        // Retrieve the UID from the provided filename.
        let uid = match from_str::<u32>(filename) {
            Some(uid) => uid,
            None => return Err(Error::simple(MessageDecodeError, "Failed to retrieve UID from filename."))
        };
        // Parse the flags from the filename.
        let unparsed_flags = flags.splitn(1, ',').skip(1).next().unwrap();
        let mut flags: Vec<Flag> = Vec::new();
        for flag in unparsed_flags.chars() {
            let flag = match flag {
                'D' => Some(Draft),
                'F' => Some(Flagged),
                'R' => Some(Answered),
                'S' => Some(Seen),
                _ => None
            };
            match flag {
                Some(flag) => flags.push(flag),
                None => { }
            };
        }

        let header_boundary = raw_contents.as_slice().find_str("\n\n").unwrap();
        let raw_header = raw_contents.as_slice().slice_to(header_boundary);
        let raw_body = raw_contents.as_slice().slice_from(header_boundary + 2);

        // Iterate over the lines of the header in reverse.
        // If a line with leading whitespace is detected, it is merged to the line before it.
        // This "unwraps" the header as indicated in RFC 2822 2.2.3
        let mut parsed_header: Vec<String> = Vec::new();
        let mut iterator = raw_header.lines().rev();
        loop {
            let line = match iterator.next() {
                Some(line) => line,
                None => break
            };
            let mut field = line.to_string();
            if line.as_slice().starts_with(" ") || line.as_slice().starts_with("\t") {
                field = field.as_slice().trim_left_chars(' ').trim_left_chars('\t').to_string();
                loop {
                    let next = iterator.next().unwrap().to_string();
                    let mut trimmed_next = next.as_slice().trim_left_chars(' ').trim_left_chars('\t').to_string();
                    // Add a space between the merged lines.
                    trimmed_next.push_str(" ".as_slice());
                    trimmed_next.push_str(field.as_slice());
                    field = trimmed_next;
                    if !next.as_slice().starts_with(" ") && !next.as_slice().starts_with("\t") {
                        break;
                    }
                }
            }

            parsed_header.push(field.to_string());
        }
        let parsed_header: Vec<&String> = parsed_header.iter().rev().collect();

        let mut headers = HashMap::new();
        for line in parsed_header.iter() {
            let split: Vec<&str> = line.as_slice().splitn(1, ':').collect();
            headers.insert(split[0].clone().to_string(), split[1].slice_from(1).clone().to_string());
        }
        // Remove the "Received" key from the HashMap.
        headers.remove(&"Received".to_string());

        // Determine whether the message is MULTIPART or not.
        let content_type = headers["Content-Type".to_string()].clone();
        let mut body = Vec::new();
        if content_type.as_slice().contains("MULTIPART") {
            let mime_boundary = {
                let value: Vec<&str> = content_type.as_slice().split_str("BOUNDARY=\"").collect();
                if value.len() < 2 { return Err(Error::simple(MessageDecodeError, "Failed to determine MULTIPART boundary.")) }
                let value: Vec<&str> = value[1].splitn(1, '"').collect();
                if value.len() < 1 { return Err(Error::simple(MessageDecodeError, "Failed to determine MULTIPART boundary.")) }
                format!("--{}--\n", value[0])
            };

            let first_content_type_index = match raw_body.find_str("Content-Type") {
                Some(val) => val,
                None => return Err(Error::simple(MessageDecodeError, "Missing Content-Type for body part"))
            };
            let raw_body = raw_body.slice_from(first_content_type_index);
            let raw_body: Vec<&str> = raw_body.split_str(mime_boundary.as_slice()).collect();
            let raw_body = raw_body.slice_to(raw_body.len() - 1);

            for part in raw_body.iter() {
                let header_boundary = part.as_slice().find_str("\n\n").unwrap();
                let header = part.as_slice().slice_to(header_boundary);
                let mut content_type = String::new();
                for line in header.lines() {
                    let split_line: Vec<&str> = line.splitn(1, ':').collect();
                    if split_line[0] == "Content-Type" {
                        let content_type_values: Vec<&str> = split_line[1].splitn(1, ';').collect();
                        content_type = content_type_values[0].slice_from(1).to_string();
                        break;
                    }
                }
                let body_part = MIMEPart {
                    mime_header: content_type.to_string(),
                    mime_body: raw_body.to_string()
                };
                body.push(body_part);
            }
        } else {
            let body_part = MIMEPart {
                mime_header: content_type.to_string(),
                mime_body: raw_body.to_string()
            };
            body.push(body_part);
        }

        let message = Message {
            uid: uid,
            path: arg_path.display().to_string(),
            headers: headers,
            body: body,
            flags: flags,
            deleted: false,
            raw_contents: raw_contents.clone()
        };

        Ok(message)
    }

    // TODO: Make sure that returning a pointer is fine.
    pub fn date_received(&self) -> &String {
        self.headers.find(&"Received-On-Date".to_string()).unwrap()
    }

    // TODO: Make sure that returning a pointer is fine.
    pub fn envelope_from(&self) -> &String {
        self.headers.find(&"From".to_string()).unwrap()
    }

    // TODO: Make sure that returning a pointer is fine.
    pub fn envelope_to(&self) -> &String {
        self.headers.find(&"To".to_string()).unwrap()
    }
}
<commit_msg>Don't assume that a message has a flags section<commit_after>use std::collections::HashMap;
use std::io::File;

use error::{
    Error, ImapResult, InternalIoError, MessageDecodeError
};

#[deriving(Show)]
enum Flag {
    Answered,
    Draft,
    Flagged,
    Seen
}

#[deriving(Show)]
pub struct Message {
    uid: u32,
    pub path: String,
    headers: HashMap<String, String>,
    body: Vec<MIMEPart>,
    flags: Vec<Flag>,
    pub deleted: bool,
    raw_contents: String
}

#[deriving(Show)]
pub struct MIMEPart {
    mime_header: String,
    mime_body: String
}

impl Message {
    pub fn parse(arg_path: &Path) -> ImapResult<Message> {
        // Load the file contents.
        let file = match File::open(arg_path) {
            Ok(mut file) => match file.read_to_end() {
                Ok(contents) => contents,
                Err(e) => return Err(Error::simple(InternalIoError(e), "Failed to read mail file."))
            },
            Err(e) => return Err(Error::simple(InternalIoError(e), "Failed to open mail file."))
        };
        let raw_contents = String::from_utf8_lossy(file.as_slice()).to_string();

        let mut path = arg_path.filename_str().unwrap().splitn(1, ':');
        let filename = path.next().unwrap();
        let path_flags = path.next();

        // Retrieve the UID from the provided filename.
        let uid = match from_str::<u32>(filename) {
            Some(uid) => uid,
            None => return Err(Error::simple(MessageDecodeError, "Failed to retrieve UID from filename."))
        };
        // Parse the flags from the filename.

        let mut flags = match path_flags {
            None => Vec::new(),
            Some(flags) => {
                let unparsed_flags = flags.splitn(1, ',').skip(1).next().unwrap();
                let mut vec_flags: Vec<Flag> = Vec::new();
                for flag in unparsed_flags.chars() {
                    let parsed_flag = match flag {
                        'D' => Some(Draft),
                        'F' => Some(Flagged),
                        'R' => Some(Answered),
                        'S' => Some(Seen),
                        _ => None
                    };
                    match parsed_flag {
                        Some(enum_flag) => vec_flags.push(enum_flag),
                        None => { }
                    }
                }
                vec_flags
            }
        };

        let header_boundary = raw_contents.as_slice().find_str("\n\n").unwrap();
        let raw_header = raw_contents.as_slice().slice_to(header_boundary);
        let raw_body = raw_contents.as_slice().slice_from(header_boundary + 2);

        // Iterate over the lines of the header in reverse.
        // If a line with leading whitespace is detected, it is merged to the line before it.
        // This "unwraps" the header as indicated in RFC 2822 2.2.3
        let mut parsed_header: Vec<String> = Vec::new();
        let mut iterator = raw_header.lines().rev();
        loop {
            let line = match iterator.next() {
                Some(line) => line,
                None => break
            };
            let mut field = line.to_string();
            if line.as_slice().starts_with(" ") || line.as_slice().starts_with("\t") {
                field = field.as_slice().trim_left_chars(' ').trim_left_chars('\t').to_string();
                loop {
                    let next = iterator.next().unwrap().to_string();
                    let mut trimmed_next = next.as_slice().trim_left_chars(' ').trim_left_chars('\t').to_string();
                    // Add a space between the merged lines.
                    trimmed_next.push_str(" ".as_slice());
                    trimmed_next.push_str(field.as_slice());
                    field = trimmed_next;
                    if !next.as_slice().starts_with(" ") && !next.as_slice().starts_with("\t") {
                        break;
                    }
                }
            }

            parsed_header.push(field.to_string());
        }
        let parsed_header: Vec<&String> = parsed_header.iter().rev().collect();

        let mut headers = HashMap::new();
        for line in parsed_header.iter() {
            let split: Vec<&str> = line.as_slice().splitn(1, ':').collect();
            headers.insert(split[0].clone().to_string(), split[1].slice_from(1).clone().to_string());
        }
        // Remove the "Received" key from the HashMap.
        headers.remove(&"Received".to_string());

        // Determine whether the message is MULTIPART or not.
        let content_type = headers["Content-Type".to_string()].clone();
        let mut body = Vec::new();
        if content_type.as_slice().contains("MULTIPART") {
            let mime_boundary = {
                let value: Vec<&str> = content_type.as_slice().split_str("BOUNDARY=\"").collect();
                if value.len() < 2 { return Err(Error::simple(MessageDecodeError, "Failed to determine MULTIPART boundary.")) }
                let value: Vec<&str> = value[1].splitn(1, '"').collect();
                if value.len() < 1 { return Err(Error::simple(MessageDecodeError, "Failed to determine MULTIPART boundary.")) }
                format!("--{}--\n", value[0])
            };

            let first_content_type_index = match raw_body.find_str("Content-Type") {
                Some(val) => val,
                None => return Err(Error::simple(MessageDecodeError, "Missing Content-Type for body part"))
            };
            let raw_body = raw_body.slice_from(first_content_type_index);
            let raw_body: Vec<&str> = raw_body.split_str(mime_boundary.as_slice()).collect();
            let raw_body = raw_body.slice_to(raw_body.len() - 1);

            for part in raw_body.iter() {
                let header_boundary = part.as_slice().find_str("\n\n").unwrap();
                let header = part.as_slice().slice_to(header_boundary);
                let mut content_type = String::new();
                for line in header.lines() {
                    let split_line: Vec<&str> = line.splitn(1, ':').collect();
                    if split_line[0] == "Content-Type" {
                        let content_type_values: Vec<&str> = split_line[1].splitn(1, ';').collect();
                        content_type = content_type_values[0].slice_from(1).to_string();
                        break;
                    }
                }
                let body_part = MIMEPart {
                    mime_header: content_type.to_string(),
                    mime_body: raw_body.to_string()
                };
                body.push(body_part);
            }
        } else {
            let body_part = MIMEPart {
                mime_header: content_type.to_string(),
                mime_body: raw_body.to_string()
            };
            body.push(body_part);
        }

        let message = Message {
            uid: uid,
            path: arg_path.display().to_string(),
            headers: headers,
            body: body,
            flags: flags,
            deleted: false,
            raw_contents: raw_contents.clone()
        };

        Ok(message)
    }

    // TODO: Make sure that returning a pointer is fine.
    pub fn date_received(&self) -> &String {
        self.headers.find(&"Received-On-Date".to_string()).unwrap()
    }

    // TODO: Make sure that returning a pointer is fine.
    pub fn envelope_from(&self) -> &String {
        self.headers.find(&"From".to_string()).unwrap()
    }

    // TODO: Make sure that returning a pointer is fine.
    pub fn envelope_to(&self) -> &String {
        self.headers.find(&"To".to_string()).unwrap()
    }
}
<|endoftext|>


<commit_before>//
// Copyright (c) 2016, Boris Popov <popov@whitekefir.ru>
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//

extern crate regex;

use logger;
use env;
use std::process::exit;
use self::regex::Regex;

//////////////////////////////////////////////////////////////////
pub struct Mounter {
    label: Option<String>
}

impl Mounter {

    pub fn new() -> Mounter {
        Mounter{label: None}
    }

    pub fn mount(&self, l: &logger::Logger, e: &env::Env) {
        //self.load_label();
        if !self.verify_label(e.getLabel()) {
            let i = format!("Label does not match {}.", e.getLabel());
            l.info(&i);
            exit(0);
        }

        //self.load_fs_type();
        //self.process();
    }

    fn verify_label(&self, templ: &str) -> bool {
        let lbl :String;
        match self.label {
            None        => { return false; },
            Some(ref l) => { lbl = l.to_string(); }
        }

        let res = Regex::new(templ);
        match res {
            Ok(re) => re.is_match(&lbl),
            _      => false
        }
    }
}
//////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////
#[test]
fn test_verify_label_01() {
    let i = Mounter{label: Some("BNC-124".to_string())};
    assert_eq!(false, i.verify_label(".*ANC.*"));
}

#[test]
fn test_verify_label_02() {
    let i = Mounter{label: Some("XANC-124".to_string())};
    assert_eq!(true, i.verify_label(".*ANC.*"));
}

#[test]
fn test_verify_label_04() {
    let i = Mounter{label: Some("ANC".to_string())};
    assert_eq!(true, i.verify_label(".*ANC.*"));
}

#[test]
fn test_verify_label_05() {
    let i = Mounter{label: Some("01234_ ANC".to_string())};
    assert_eq!(true, i.verify_label(".*ANC.*"));
}

#[test]
fn test_verify_label_06() {
    let i = Mounter{label: Some("01234_ ANC 782883 ".to_string())};
    assert_eq!(true, i.verify_label(".*ANC.*"));
}

#[test]
fn test_verify_label_07() {
    let i = Mounter{label: Some(" ANC 782883 ".to_string())};
    assert_eq!(true, i.verify_label(".*ANC.*"));
}

#[test]
fn test_verify_label_08() {
    let i = Mounter{label: Some("ANC---!782883 ".to_string())};
    assert_eq!(true, i.verify_label(".*ANC.*"));
}

#[test]
fn test_verify_label_09() {
    let i = Mounter{label: Some("01234_ NC 782883 ".to_string())};
    assert_eq!(false, i.verify_label(".*ANC.*"));
}
//////////////////////////////////////////////////////////////////
<commit_msg>workn in progress<commit_after>//
// Copyright (c) 2016, Boris Popov <popov@whitekefir.ru>
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//

extern crate regex;

use logger;
use env;
use std::process::exit;
use self::regex::Regex;
use blkid;

//////////////////////////////////////////////////////////////////
pub struct Mounter {
    label:  Option<String>
}

impl Mounter {

    pub fn new() -> Mounter {
        Mounter{label: None}
    }

    pub fn mount(&mut self, l: &logger::Logger, e: &env::Env) {
        self.load_label(e.getDevice(), l);
        if !self.verify_label(e.getLabel()) {
            let i = format!("Label does not match {}.", e.getLabel());
            l.info(&i);
            exit(0);
        }
        //
        //TODO
        //
        //self.load_fs_type();
        //self.process();
    }

    fn verify_label(&self, templ: &str) -> bool {
        let lbl :String;
        match self.label {
            None        => { return false; },
            Some(ref l) => { lbl = l.to_string(); }
        }

        let res = Regex::new(templ);
        match res {
            Ok(re) => re.is_match(&lbl),
            _      => false
        }
    }

    fn load_label(&mut self, dev: &str, l: &logger::Logger) {
        let prober_r = blkid::Prober::new(dev);
        //
        //TODO
        //
    }
}
//////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////
#[test]
fn test_verify_label_01() {
    let i = Mounter{label: Some("BNC-124".to_string())};
    assert_eq!(false, i.verify_label(".*ANC.*"));
}

#[test]
fn test_verify_label_02() {
    let i = Mounter{label: Some("XANC-124".to_string())};
    assert_eq!(true, i.verify_label(".*ANC.*"));
}

#[test]
fn test_verify_label_04() {
    let i = Mounter{label: Some("ANC".to_string())};
    assert_eq!(true, i.verify_label(".*ANC.*"));
}

#[test]
fn test_verify_label_05() {
    let i = Mounter{label: Some("01234_ ANC".to_string())};
    assert_eq!(true, i.verify_label(".*ANC.*"));
}

#[test]
fn test_verify_label_06() {
    let i = Mounter{label: Some("01234_ ANC 782883 ".to_string())};
    assert_eq!(true, i.verify_label(".*ANC.*"));
}

#[test]
fn test_verify_label_07() {
    let i = Mounter{label: Some(" ANC 782883 ".to_string())};
    assert_eq!(true, i.verify_label(".*ANC.*"));
}

#[test]
fn test_verify_label_08() {
    let i = Mounter{label: Some("ANC---!782883 ".to_string())};
    assert_eq!(true, i.verify_label(".*ANC.*"));
}

#[test]
fn test_verify_label_09() {
    let i = Mounter{label: Some("01234_ NC 782883 ".to_string())};
    assert_eq!(false, i.verify_label(".*ANC.*"));
}
//////////////////////////////////////////////////////////////////
<|endoftext|>


<commit_before>// Integration with Musashi
extern crate libc;

// Register enum copied from Musashi's m68k_register_t enum
#[repr(C)]
#[derive(Copy, Clone)]
pub enum Register {
	/* Real registers */
	D0,		/* Data registers */
	D1,
	D2,
	D3,
	D4,
	D5,
	D6,
	D7,
	A0,		/* Address registers */
	A1,
	A2,
	A3,
	A4,
	A5,
	A6,
	A7,
	PC,		/* Program Counter */
	SR,		/* Status Register */
	SP,		/* The current Stack Pointer (located in A7) */
	USP,		/* User Stack Pointer */
	ISP,		/* Interrupt Stack Pointer */
	MSP,		/* Master Stack Pointer */
	SFC,		/* Source Function Code */
	DFC,		/* Destination Function Code */
	VBR,		/* Vector Base Register */
	CACR,		/* Cache Control Register */
	CAAR,		/* Cache Address Register */

	/* Assumed registers */
	/* These are cheat registers which emulate the 1-longword prefetch
	 * present in the 68000 and 68010.
	 */
	PrefAddr,	/* Last prefetch address */
	PrefData,	/* Last prefetch data */

	/* Convenience registers */
	PPC,		/* Previous value in the program counter */
	IR,			/* Instruction register */
	CpuType	/* Type of CPU being run */
}

#[repr(C)]
#[derive(Copy, Clone)]
enum CpuType
{
	Invalid,
	M68000,
	M68010,
	M68EC020,
	M68020,
	M68030,		/* Supported by disassembler ONLY */
	M68040		/* Supported by disassembler ONLY */
}

#[link(name = "musashi", kind = "static")]
extern {
	fn m68k_init();
	fn m68k_set_cpu_type(cputype: CpuType);
	fn m68k_pulse_reset();
	fn m68k_execute(num_cycles: i32) -> i32;
	fn m68k_get_reg(context: *mut libc::c_void, regnum: Register) -> u32;
	fn m68k_set_reg(regnum: Register, value: u32);
}
#[derive(Copy, Clone, Debug, PartialEq)]
enum Operation {
	None,
    ReadByte(u32),
    ReadWord(u32),
    ReadLong(u32),
    WriteByte(u32, u32),
    WriteWord(u32, u32),
    WriteLong(u32, u32),
}
static mut musashi_memory:  [u8; 1024] = [0u8; 1024];
// as statics are not allowed to have destructors, allocate a
// big enough array to hold the small number of operations
// expected from executing a very limited number of opcodes
static mut musashi_opcount: usize = 0;
static mut musashi_ops: [Operation; 128] = [Operation::None; 128];

unsafe fn register_op(op: Operation) {
	if(musashi_opcount < musashi_ops.len()) {
		musashi_ops[musashi_opcount] = op;
		musashi_opcount += 1;
	}
}
// callbacks from Musashi
#[no_mangle]
pub extern fn cpu_read_byte(address: u32) -> u32 {
	let op = Operation::ReadByte(address);
	let address = address as usize;
	unsafe {
		register_op(op);
		musashi_memory[address] as u32
	}
}
#[no_mangle]
pub extern fn cpu_read_word(address: u32) -> u32 {
	let op = Operation::ReadWord(address);
	let address = address as usize;
	unsafe {
		register_op(op);
		((musashi_memory[address+0] as u32) << 8
		|(musashi_memory[address+1] as u32) << 0) as u32
	}
}
#[no_mangle]
pub extern fn cpu_read_long(address: u32) -> u32 {
	let op = Operation::ReadLong(address);
	let address = address as usize;
	unsafe {
		register_op(op);
		((musashi_memory[address+0] as u32) << 24
		|(musashi_memory[address+1] as u32) << 16
		|(musashi_memory[address+2] as u32) <<  8
		|(musashi_memory[address+3] as u32) <<  0) as u32
	}
}

#[no_mangle]
pub extern fn cpu_write_byte(address: u32, value: u32) {
	let op = Operation::WriteByte(address, value);
	let address = address as usize;
	unsafe {
		register_op(op);
		musashi_memory[address+0] = (value & 0xff) as u8;
	}
}
#[no_mangle]
pub extern fn cpu_write_word(address: u32, value: u32) {
	let op = Operation::WriteWord(address, value);
	let address = address as usize;
	unsafe {
		register_op(op);
		musashi_memory[address+0] = (value & 0xff00 >> 8) as u8;
		musashi_memory[address+1] = (value & 0x00ff >> 0) as u8;
	}
}
#[no_mangle]
pub extern fn cpu_write_long(address: u32, value: u32) {
	let op = Operation::WriteLong(address, value);
	let address = address as usize;
	unsafe {
		register_op(op);
		musashi_memory[address+0] = (value & 0xff000000 >> 24) as u8;
		musashi_memory[address+1] = (value & 0x00ff0000 >> 16) as u8;
		musashi_memory[address+2] = (value & 0x0000ff00 >>  8) as u8;
		musashi_memory[address+3] = (value & 0x000000ff >>  0) as u8;
	}
}

#[no_mangle]
pub extern fn cpu_pulse_reset() {panic!("pr")}
#[no_mangle]
pub extern fn cpu_long_branch() {}
#[no_mangle]
pub extern fn cpu_set_fc(fc: u32) {
	//println!("set_fc {}", fc)
}
#[no_mangle]
pub extern fn cpu_irq_ack(level: i32) -> i32 {panic!("ia")}
#[no_mangle]
pub extern fn cpu_instr_callback() {}

use std::ptr;

pub fn experimental_communication() {
	unsafe {
		m68k_init();
		m68k_set_cpu_type(CpuType::M68000);
		m68k_set_reg(Register::D0, 123);
		println!("D0: {}", m68k_get_reg(ptr::null_mut(), Register::D0));
	}
}

pub fn roundtrip_register(reg: Register, value: u32) -> u32 {
	unsafe {
		m68k_init();
		m68k_set_cpu_type(CpuType::M68000);
		m68k_set_reg(reg, value);
		m68k_get_reg(ptr::null_mut(), reg)
	}
}

use cpu::Core;

pub fn execute1(core: &mut Core) {
	unsafe {
		m68k_init();
		m68k_set_cpu_type(CpuType::M68000);
		// m68k_pulse_reset(); causes irrelevant reads from 0x00000000 to set PC/SP, a jump to PC,
		// and resetting of state, which is unneeded because we override that state anyway
		let regs = [Register::D0, Register::D1, Register::D2, Register::D3, Register::D4, Register::D5, Register::D6, Register::D7, Register::A0, Register::A1, Register::A2, Register::A3, Register::A4, Register::A5, Register::A6, Register::A7];
		for (i, &reg) in regs.iter().enumerate() {m68k_set_reg(reg, core.dar[i]);}
		m68k_set_reg(Register::PC, core.pc);
		m68k_set_reg(Register::SP, core.sp);
		m68k_set_reg(Register::SR, core.status_register());
		unsafe {
			for (i,b) in core.mem.iter().enumerate() {
				musashi_memory[i] = *b;
			}
		}
		m68k_execute(1);

		for (i, &reg) in regs.iter().enumerate() {
			core.dar[i] = m68k_get_reg(ptr::null_mut(), reg);
		}
		core.pc = m68k_get_reg(ptr::null_mut(), Register::PC);
		core.sp = m68k_get_reg(ptr::null_mut(), Register::SP);
		core.sr_to_flags(m68k_get_reg(ptr::null_mut(), Register::SR));
	}
}

#[cfg(test)]
mod tests {
	use super::*;
	use super::musashi_memory;
	use super::musashi_ops;
	use super::musashi_opcount;
	use super::Operation;
	use cpu::Core;

	fn get_ops() -> Vec<Operation> {
		let mut res: Vec<Operation> = vec![];
		unsafe {
			for i in 0..musashi_opcount {
				res.push(musashi_ops[i]);
			}
		}
		res
	}
	macro_rules! core_eq {
	    ($left:ident , $right:ident . $field:ident [ $index:expr ]) => ({
	        match (&($left.$field[$index]), &($right.$field[$index])) {
	            (left_val, right_val) => {
	                if !(*left_val == *right_val) {
	                    panic!("core coherence failed: `{}[{}]` differs)` \
	                           ({}: `{:?}`, {}: `{:?}`)", stringify!($field), $index, stringify!($left), left_val, stringify!($right), right_val)
	                }
	            }
	        }
	    });
	    ($left:ident , $right:ident . $field:ident () ) => ({
	        match (&($left.$field()), &($right.$field())) {
	            (left_val, right_val) => {
	                if !(*left_val == *right_val) {
	                    panic!("core coherence failed: `{}()` differs)` \
	                           ({}: `{:?}`, {}: `{:?}`)", stringify!($field), stringify!($left), left_val, stringify!($right), right_val)
	                }
	            }
	        }
	    });
	    ($left:ident , $right:ident . $field:ident) => ({
	        match (&($left.$field), &($right.$field)) {
	            (left_val, right_val) => {
	                if !(*left_val == *right_val) {
	                    panic!("core coherence failed: '{}' differs)` \
	                           ({}: `{:?}`, {}: `{:?}`)", stringify!($field), stringify!($left), left_val, stringify!($right), right_val)
	                }
	            }
	        }
	    })
	}
	fn assert_cores_equal(musashi: &Core, r68k: &Core, pc: u32) {
		core_eq!(musashi, r68k.pc);
		core_eq!(musashi, r68k.sp);
		for i in 0..16 {
			core_eq!(musashi, r68k.dar[i]);
		}
		core_eq!(musashi, r68k.flags());
		core_eq!(musashi, r68k.status_register());

		let ops = get_ops();
		assert_eq!(1, ops.len());
		assert_eq!(Operation::ReadLong(pc), ops[0]);
	}

	#[test]
	fn roundtrip_d0() {
		assert_eq!(256, roundtrip_register(Register::D0, 256));
	}

	#[test]
	fn roundtrip_abcd_rr() {
		let pc = 0x40;
		let mut cpu = Core::new_mem(pc, &[0xc3, 0x00]);
		cpu.dar[0] = 0x16;
		cpu.dar[1] = 0x26;
		execute1(&mut cpu);

		// 16 + 26 is 42
		assert_eq!(0x42, cpu.dar[1]);

		let ops = get_ops();
		assert_eq!(1, ops.len());
		assert_eq!(Operation::ReadLong(pc), ops[0]);
	}

	#[test]
	fn compare_abcd_rr() {
		let pc = 0x40;
		let mut musashi = Core::new_mem(pc, &[0xc3, 0x00]);
		musashi.dar[0] = 0x16;
		musashi.dar[1] = 0x26;

		let mut r68k = musashi.clone(); // so very self-aware!
		execute1(&mut musashi);
		r68k.execute1();

		assert_cores_equal(&musashi, &r68k, pc);
	}}<commit_msg>Allow dead code for enums<commit_after>// Integration with Musashi
extern crate libc;

// Register enum copied from Musashi's m68k_register_t enum
#[repr(C)]
#[derive(Copy, Clone)]
#[allow(dead_code)]
pub enum Register {
	/* Real registers */
	D0,		/* Data registers */
	D1,
	D2,
	D3,
	D4,
	D5,
	D6,
	D7,
	A0,		/* Address registers */
	A1,
	A2,
	A3,
	A4,
	A5,
	A6,
	A7,
	PC,		/* Program Counter */
	SR,		/* Status Register */
	SP,		/* The current Stack Pointer (located in A7) */
	USP,		/* User Stack Pointer */
	ISP,		/* Interrupt Stack Pointer */
	MSP,		/* Master Stack Pointer */
	SFC,		/* Source Function Code */
	DFC,		/* Destination Function Code */
	VBR,		/* Vector Base Register */
	CACR,		/* Cache Control Register */
	CAAR,		/* Cache Address Register */

	/* Assumed registers */
	/* These are cheat registers which emulate the 1-longword prefetch
	 * present in the 68000 and 68010.
	 */
	PrefAddr,	/* Last prefetch address */
	PrefData,	/* Last prefetch data */

	/* Convenience registers */
	PPC,		/* Previous value in the program counter */
	IR,			/* Instruction register */
	CpuType	/* Type of CPU being run */
}

#[repr(C)]
#[derive(Copy, Clone)]
#[allow(dead_code)]
enum CpuType
{
	Invalid,
	M68000,
	M68010,
	M68EC020,
	M68020,
	M68030,		/* Supported by disassembler ONLY */
	M68040		/* Supported by disassembler ONLY */
}

#[link(name = "musashi", kind = "static")]
extern {
	fn m68k_init();
	fn m68k_set_cpu_type(cputype: CpuType);
	fn m68k_pulse_reset();
	fn m68k_execute(num_cycles: i32) -> i32;
	fn m68k_get_reg(context: *mut libc::c_void, regnum: Register) -> u32;
	fn m68k_set_reg(regnum: Register, value: u32);
}
#[derive(Copy, Clone, Debug, PartialEq)]
enum Operation {
	None,
    ReadByte(u32),
    ReadWord(u32),
    ReadLong(u32),
    WriteByte(u32, u32),
    WriteWord(u32, u32),
    WriteLong(u32, u32),
}
static mut musashi_memory:  [u8; 1024] = [0u8; 1024];
// as statics are not allowed to have destructors, allocate a
// big enough array to hold the small number of operations
// expected from executing a very limited number of opcodes
static mut musashi_opcount: usize = 0;
static mut musashi_ops: [Operation; 128] = [Operation::None; 128];

unsafe fn register_op(op: Operation) {
	if(musashi_opcount < musashi_ops.len()) {
		musashi_ops[musashi_opcount] = op;
		musashi_opcount += 1;
	}
}
// callbacks from Musashi
#[no_mangle]
pub extern fn cpu_read_byte(address: u32) -> u32 {
	let op = Operation::ReadByte(address);
	let address = address as usize;
	unsafe {
		register_op(op);
		musashi_memory[address] as u32
	}
}
#[no_mangle]
pub extern fn cpu_read_word(address: u32) -> u32 {
	let op = Operation::ReadWord(address);
	let address = address as usize;
	unsafe {
		register_op(op);
		((musashi_memory[address+0] as u32) << 8
		|(musashi_memory[address+1] as u32) << 0) as u32
	}
}
#[no_mangle]
pub extern fn cpu_read_long(address: u32) -> u32 {
	let op = Operation::ReadLong(address);
	let address = address as usize;
	unsafe {
		register_op(op);
		((musashi_memory[address+0] as u32) << 24
		|(musashi_memory[address+1] as u32) << 16
		|(musashi_memory[address+2] as u32) <<  8
		|(musashi_memory[address+3] as u32) <<  0) as u32
	}
}

#[no_mangle]
pub extern fn cpu_write_byte(address: u32, value: u32) {
	let op = Operation::WriteByte(address, value);
	let address = address as usize;
	unsafe {
		register_op(op);
		musashi_memory[address+0] = (value & 0xff) as u8;
	}
}
#[no_mangle]
pub extern fn cpu_write_word(address: u32, value: u32) {
	let op = Operation::WriteWord(address, value);
	let address = address as usize;
	unsafe {
		register_op(op);
		musashi_memory[address+0] = (value & 0xff00 >> 8) as u8;
		musashi_memory[address+1] = (value & 0x00ff >> 0) as u8;
	}
}
#[no_mangle]
pub extern fn cpu_write_long(address: u32, value: u32) {
	let op = Operation::WriteLong(address, value);
	let address = address as usize;
	unsafe {
		register_op(op);
		musashi_memory[address+0] = (value & 0xff000000 >> 24) as u8;
		musashi_memory[address+1] = (value & 0x00ff0000 >> 16) as u8;
		musashi_memory[address+2] = (value & 0x0000ff00 >>  8) as u8;
		musashi_memory[address+3] = (value & 0x000000ff >>  0) as u8;
	}
}

#[no_mangle]
pub extern fn cpu_pulse_reset() {panic!("pr")}
#[no_mangle]
pub extern fn cpu_long_branch() {}
#[no_mangle]
pub extern fn cpu_set_fc(fc: u32) {
	//println!("set_fc {}", fc)
}
#[no_mangle]
pub extern fn cpu_irq_ack(level: i32) -> i32 {panic!("ia")}
#[no_mangle]
pub extern fn cpu_instr_callback() {}

use std::ptr;

pub fn experimental_communication() {
	unsafe {
		m68k_init();
		m68k_set_cpu_type(CpuType::M68000);
		m68k_set_reg(Register::D0, 123);
		println!("D0: {}", m68k_get_reg(ptr::null_mut(), Register::D0));
	}
}

pub fn roundtrip_register(reg: Register, value: u32) -> u32 {
	unsafe {
		m68k_init();
		m68k_set_cpu_type(CpuType::M68000);
		m68k_set_reg(reg, value);
		m68k_get_reg(ptr::null_mut(), reg)
	}
}

use cpu::Core;

pub fn execute1(core: &mut Core) {
	unsafe {
		m68k_init();
		m68k_set_cpu_type(CpuType::M68000);
		// m68k_pulse_reset(); causes irrelevant reads from 0x00000000 to set PC/SP, a jump to PC,
		// and resetting of state, which is unneeded because we override that state anyway
		let regs = [Register::D0, Register::D1, Register::D2, Register::D3, Register::D4, Register::D5, Register::D6, Register::D7, Register::A0, Register::A1, Register::A2, Register::A3, Register::A4, Register::A5, Register::A6, Register::A7];
		for (i, &reg) in regs.iter().enumerate() {m68k_set_reg(reg, core.dar[i]);}
		m68k_set_reg(Register::PC, core.pc);
		m68k_set_reg(Register::SP, core.sp);
		m68k_set_reg(Register::SR, core.status_register());
		unsafe {
			for (i,b) in core.mem.iter().enumerate() {
				musashi_memory[i] = *b;
			}
		}
		m68k_execute(1);

		for (i, &reg) in regs.iter().enumerate() {
			core.dar[i] = m68k_get_reg(ptr::null_mut(), reg);
		}
		core.pc = m68k_get_reg(ptr::null_mut(), Register::PC);
		core.sp = m68k_get_reg(ptr::null_mut(), Register::SP);
		core.sr_to_flags(m68k_get_reg(ptr::null_mut(), Register::SR));
	}
}

#[cfg(test)]
mod tests {
	use super::*;
	use super::musashi_memory;
	use super::musashi_ops;
	use super::musashi_opcount;
	use super::Operation;
	use cpu::Core;

	fn get_ops() -> Vec<Operation> {
		let mut res: Vec<Operation> = vec![];
		unsafe {
			for i in 0..musashi_opcount {
				res.push(musashi_ops[i]);
			}
		}
		res
	}
	macro_rules! core_eq {
	    ($left:ident , $right:ident . $field:ident [ $index:expr ]) => ({
	        match (&($left.$field[$index]), &($right.$field[$index])) {
	            (left_val, right_val) => {
	                if !(*left_val == *right_val) {
	                    panic!("core coherence failed: `{}[{}]` differs)` \
	                           ({}: `{:?}`, {}: `{:?}`)", stringify!($field), $index, stringify!($left), left_val, stringify!($right), right_val)
	                }
	            }
	        }
	    });
	    ($left:ident , $right:ident . $field:ident () ) => ({
	        match (&($left.$field()), &($right.$field())) {
	            (left_val, right_val) => {
	                if !(*left_val == *right_val) {
	                    panic!("core coherence failed: `{}()` differs)` \
	                           ({}: `{:?}`, {}: `{:?}`)", stringify!($field), stringify!($left), left_val, stringify!($right), right_val)
	                }
	            }
	        }
	    });
	    ($left:ident , $right:ident . $field:ident) => ({
	        match (&($left.$field), &($right.$field)) {
	            (left_val, right_val) => {
	                if !(*left_val == *right_val) {
	                    panic!("core coherence failed: '{}' differs)` \
	                           ({}: `{:?}`, {}: `{:?}`)", stringify!($field), stringify!($left), left_val, stringify!($right), right_val)
	                }
	            }
	        }
	    })
	}
	fn assert_cores_equal(musashi: &Core, r68k: &Core, pc: u32) {
		core_eq!(musashi, r68k.pc);
		core_eq!(musashi, r68k.sp);
		for i in 0..16 {
			core_eq!(musashi, r68k.dar[i]);
		}
		core_eq!(musashi, r68k.flags());
		core_eq!(musashi, r68k.status_register());

		let ops = get_ops();
		assert_eq!(1, ops.len());
		assert_eq!(Operation::ReadLong(pc), ops[0]);
	}

	#[test]
	fn roundtrip_d0() {
		assert_eq!(256, roundtrip_register(Register::D0, 256));
	}

	#[test]
	fn roundtrip_abcd_rr() {
		let pc = 0x40;
		let mut cpu = Core::new_mem(pc, &[0xc3, 0x00]);
		cpu.dar[0] = 0x16;
		cpu.dar[1] = 0x26;
		execute1(&mut cpu);

		// 16 + 26 is 42
		assert_eq!(0x42, cpu.dar[1]);

		let ops = get_ops();
		assert_eq!(1, ops.len());
		assert_eq!(Operation::ReadLong(pc), ops[0]);
	}

	#[test]
	fn compare_abcd_rr() {
		let pc = 0x40;
		let mut musashi = Core::new_mem(pc, &[0xc3, 0x00]);
		musashi.dar[0] = 0x16;
		musashi.dar[1] = 0x26;

		let mut r68k = musashi.clone(); // so very self-aware!
		execute1(&mut musashi);
		r68k.execute1();

		assert_cores_equal(&musashi, &r68k, pc);
	}}<|endoftext|>


<commit_before>// Integration with Musashi
extern crate libc;

// Register enum copied from Musashi's m68k_register_t enum
#[repr(C)]
#[derive(Copy, Clone)]
#[allow(dead_code)]
pub enum Register {
	/* Real registers */
	D0,		/* Data registers */
	D1,
	D2,
	D3,
	D4,
	D5,
	D6,
	D7,
	A0,		/* Address registers */
	A1,
	A2,
	A3,
	A4,
	A5,
	A6,
	A7,
	PC,		/* Program Counter */
	SR,		/* Status Register */
	SP,		/* The current Stack Pointer (located in A7) */
	USP,		/* User Stack Pointer */
	ISP,		/* Interrupt Stack Pointer */
	MSP,		/* Master Stack Pointer */
	SFC,		/* Source Function Code */
	DFC,		/* Destination Function Code */
	VBR,		/* Vector Base Register */
	CACR,		/* Cache Control Register */
	CAAR,		/* Cache Address Register */

	/* Assumed registers */
	/* These are cheat registers which emulate the 1-longword prefetch
	 * present in the 68000 and 68010.
	 */
	PrefAddr,	/* Last prefetch address */
	PrefData,	/* Last prefetch data */

	/* Convenience registers */
	PPC,		/* Previous value in the program counter */
	IR,			/* Instruction register */
	CpuType	/* Type of CPU being run */
}

#[repr(C)]
#[derive(Copy, Clone)]
#[allow(dead_code)]
enum CpuType
{
	Invalid,
	M68000,
	M68010,
	M68EC020,
	M68020,
	M68030,		/* Supported by disassembler ONLY */
	M68040		/* Supported by disassembler ONLY */
}

#[link(name = "musashi", kind = "static")]
extern {
	fn m68k_init();
	fn m68k_set_cpu_type(cputype: CpuType);
	fn m68k_pulse_reset();
	fn m68k_execute(num_cycles: i32) -> i32;
	fn m68k_get_reg(context: *mut libc::c_void, regnum: Register) -> u32;
	fn m68k_set_reg(regnum: Register, value: u32);
}
#[derive(Copy, Clone, Debug, PartialEq)]
enum Operation {
	None,
    ReadByte(u32),
    ReadWord(u32),
    ReadLong(u32),
    WriteByte(u32, u32),
    WriteWord(u32, u32),
    WriteLong(u32, u32),
}
static mut musashi_memory:  [u8; 1024] = [0u8; 1024];
// as statics are not allowed to have destructors, allocate a
// big enough array to hold the small number of operations
// expected from executing a very limited number of opcodes
static mut musashi_opcount: usize = 0;
static mut musashi_ops: [Operation; 128] = [Operation::None; 128];

unsafe fn register_op(op: Operation) {
	if musashi_opcount < musashi_ops.len() {
		musashi_ops[musashi_opcount] = op;
		musashi_opcount += 1;
	}
}
// callbacks from Musashi
#[no_mangle]
pub extern fn cpu_read_byte(address: u32) -> u32 {
	let op = Operation::ReadByte(address);
	let address = address as usize;
	unsafe {
		register_op(op);
		musashi_memory[address] as u32
	}
}
#[no_mangle]
pub extern fn cpu_read_word(address: u32) -> u32 {
	let op = Operation::ReadWord(address);
	let address = address as usize;
	unsafe {
		register_op(op);
		((musashi_memory[address+0] as u32) << 8
		|(musashi_memory[address+1] as u32) << 0) as u32
	}
}
#[no_mangle]
pub extern fn cpu_read_long(address: u32) -> u32 {
	let op = Operation::ReadLong(address);
	let address = address as usize;
	unsafe {
		register_op(op);
		((musashi_memory[address+0] as u32) << 24
		|(musashi_memory[address+1] as u32) << 16
		|(musashi_memory[address+2] as u32) <<  8
		|(musashi_memory[address+3] as u32) <<  0) as u32
	}
}

#[no_mangle]
pub extern fn cpu_write_byte(address: u32, value: u32) {
	let op = Operation::WriteByte(address, value);
	let address = address as usize;
	unsafe {
		register_op(op);
		musashi_memory[address+0] = (value & 0xff) as u8;
	}
}
#[no_mangle]
pub extern fn cpu_write_word(address: u32, value: u32) {
	let op = Operation::WriteWord(address, value);
	let address = address as usize;
	unsafe {
		register_op(op);
		musashi_memory[address+0] = (value & 0xff00 >> 8) as u8;
		musashi_memory[address+1] = (value & 0x00ff >> 0) as u8;
	}
}
#[no_mangle]
pub extern fn cpu_write_long(address: u32, value: u32) {
	let op = Operation::WriteLong(address, value);
	let address = address as usize;
	unsafe {
		register_op(op);
		musashi_memory[address+0] = (value & 0xff000000 >> 24) as u8;
		musashi_memory[address+1] = (value & 0x00ff0000 >> 16) as u8;
		musashi_memory[address+2] = (value & 0x0000ff00 >>  8) as u8;
		musashi_memory[address+3] = (value & 0x000000ff >>  0) as u8;
	}
}

#[no_mangle]
pub extern fn cpu_pulse_reset() {panic!("pr")}
#[no_mangle]
pub extern fn cpu_long_branch() {}
#[no_mangle]
pub extern fn cpu_set_fc(fc: u32) {
	//println!("set_fc {}", fc)
}
#[no_mangle]
pub extern fn cpu_irq_ack(level: i32) -> i32 {panic!("ia")}
#[no_mangle]
pub extern fn cpu_instr_callback() {}

use std::ptr;

pub fn experimental_communication() {
	unsafe {
		m68k_init();
		m68k_set_cpu_type(CpuType::M68000);
		m68k_set_reg(Register::D0, 123);
		println!("D0: {}", m68k_get_reg(ptr::null_mut(), Register::D0));
	}
}

pub fn roundtrip_register(reg: Register, value: u32) -> u32 {
	unsafe {
		m68k_init();
		m68k_set_cpu_type(CpuType::M68000);
		m68k_set_reg(reg, value);
		m68k_get_reg(ptr::null_mut(), reg)
	}
}

use cpu::Core;

pub fn execute1(core: &mut Core) {
	unsafe {
		m68k_init();
		m68k_set_cpu_type(CpuType::M68000);
		m68k_pulse_reset();
		// Resetting opcount, because m68k_pulse_reset causes irrelevant
		// reads from 0x00000000 to set PC/SP, a jump to PC and
		// resetting of state. But we don't want to test those ops.
		musashi_opcount = 0;
		let regs = [Register::D0, Register::D1, Register::D2, Register::D3, Register::D4, Register::D5, Register::D6, Register::D7, Register::A0, Register::A1, Register::A2, Register::A3, Register::A4, Register::A5, Register::A6, Register::A7];
		for (i, &reg) in regs.iter().enumerate() {m68k_set_reg(reg, core.dar[i]);}
		m68k_set_reg(Register::PC, core.pc);
		m68k_set_reg(Register::SP, core.sp);
		m68k_set_reg(Register::SR, core.status_register());
		unsafe {
			for (i,b) in core.mem.iter().enumerate() {
				musashi_memory[i] = *b;
			}
		}
		m68k_execute(1);

		for (i, &reg) in regs.iter().enumerate() {
			core.dar[i] = m68k_get_reg(ptr::null_mut(), reg);
		}
		core.pc = m68k_get_reg(ptr::null_mut(), Register::PC);
		core.sp = m68k_get_reg(ptr::null_mut(), Register::SP);
		core.sr_to_flags(m68k_get_reg(ptr::null_mut(), Register::SR));
	}
}

#[cfg(test)]
mod tests {
	use super::*;
	use super::musashi_memory;
	use super::musashi_ops;
	use super::musashi_opcount;
	use super::Operation;
	use cpu::Core;

	fn get_ops() -> Vec<Operation> {
		let mut res: Vec<Operation> = vec![];
		unsafe {
			for i in 0..musashi_opcount {
				res.push(musashi_ops[i]);
			}
		}
		res
	}
	macro_rules! core_eq {
	    ($left:ident , $right:ident . $field:ident [ $index:expr ]) => ({
	        match (&($left.$field[$index]), &($right.$field[$index])) {
	            (left_val, right_val) => {
	                if !(*left_val == *right_val) {
	                    panic!("core coherence failed: `{}[{}]` differs)` \
	                           ({}: `{:?}`, {}: `{:?}`)", stringify!($field), $index, stringify!($left), left_val, stringify!($right), right_val)
	                }
	            }
	        }
	    });
	    ($left:ident , $right:ident . $field:ident () ) => ({
	        match (&($left.$field()), &($right.$field())) {
	            (left_val, right_val) => {
	                if !(*left_val == *right_val) {
	                    panic!("core coherence failed: `{}()` differs)` \
	                           ({}: `{:?}`, {}: `{:?}`)", stringify!($field), stringify!($left), left_val, stringify!($right), right_val)
	                }
	            }
	        }
	    });
	    ($left:ident , $right:ident . $field:ident) => ({
	        match (&($left.$field), &($right.$field)) {
	            (left_val, right_val) => {
	                if !(*left_val == *right_val) {
	                    panic!("core coherence failed: '{}' differs)` \
	                           ({}: `{:?}`, {}: `{:?}`)", stringify!($field), stringify!($left), left_val, stringify!($right), right_val)
	                }
	            }
	        }
	    })
	}
	fn assert_cores_equal(musashi: &Core, r68k: &Core, pc: u32) {
		core_eq!(musashi, r68k.pc);
		core_eq!(musashi, r68k.sp);
		for i in 0..16 {
			core_eq!(musashi, r68k.dar[i]);
		}
		core_eq!(musashi, r68k.flags());
		core_eq!(musashi, r68k.status_register());

		let ops = get_ops();
		assert_eq!(1, ops.len());
		assert_eq!(Operation::ReadLong(pc), ops[0]);
	}

	#[test]
	fn roundtrip_d0() {
		assert_eq!(256, roundtrip_register(Register::D0, 256));
	}

	#[test]
	fn roundtrip_abcd_rr() {
		let pc = 0x40;
		let mut cpu = Core::new_mem(pc, &[0xc3, 0x00]);
		cpu.dar[0] = 0x16;
		cpu.dar[1] = 0x26;
		execute1(&mut cpu);

		// 16 + 26 is 42
		assert_eq!(0x42, cpu.dar[1]);

		let ops = get_ops();
		assert_eq!(1, ops.len());
		assert_eq!(Operation::ReadLong(pc), ops[0]);
	}

	#[test]
	fn compare_abcd_rr() {
		let pc = 0x40;
		let mut musashi = Core::new_mem(pc, &[0xc3, 0x00]);
		musashi.dar[0] = 0x16;
		musashi.dar[1] = 0x26;

		let mut r68k = musashi.clone(); // so very self-aware!
		execute1(&mut musashi);
		r68k.execute1();

		assert_cores_equal(&musashi, &r68k, pc);
	}}<commit_msg>Cleanup of execute1<commit_after>// Integration with Musashi
extern crate libc;

// Register enum copied from Musashi's m68k_register_t enum
#[repr(C)]
#[derive(Copy, Clone)]
#[allow(dead_code)]
pub enum Register {
	/* Real registers */
	D0,		/* Data registers */
	D1,
	D2,
	D3,
	D4,
	D5,
	D6,
	D7,
	A0,		/* Address registers */
	A1,
	A2,
	A3,
	A4,
	A5,
	A6,
	A7,
	PC,		/* Program Counter */
	SR,		/* Status Register */
	SP,		/* The current Stack Pointer (located in A7) */
	USP,		/* User Stack Pointer */
	ISP,		/* Interrupt Stack Pointer */
	MSP,		/* Master Stack Pointer */
	SFC,		/* Source Function Code */
	DFC,		/* Destination Function Code */
	VBR,		/* Vector Base Register */
	CACR,		/* Cache Control Register */
	CAAR,		/* Cache Address Register */

	/* Assumed registers */
	/* These are cheat registers which emulate the 1-longword prefetch
	 * present in the 68000 and 68010.
	 */
	PrefAddr,	/* Last prefetch address */
	PrefData,	/* Last prefetch data */

	/* Convenience registers */
	PPC,		/* Previous value in the program counter */
	IR,			/* Instruction register */
	CpuType	/* Type of CPU being run */
}

#[repr(C)]
#[derive(Copy, Clone)]
#[allow(dead_code)]
enum CpuType
{
	Invalid,
	M68000,
	M68010,
	M68EC020,
	M68020,
	M68030,		/* Supported by disassembler ONLY */
	M68040		/* Supported by disassembler ONLY */
}

#[link(name = "musashi", kind = "static")]
extern {
	fn m68k_init();
	fn m68k_set_cpu_type(cputype: CpuType);
	fn m68k_pulse_reset();
	fn m68k_execute(num_cycles: i32) -> i32;
	fn m68k_get_reg(context: *mut libc::c_void, regnum: Register) -> u32;
	fn m68k_set_reg(regnum: Register, value: u32);
}
#[derive(Copy, Clone, Debug, PartialEq)]
enum Operation {
	None,
    ReadByte(u32),
    ReadWord(u32),
    ReadLong(u32),
    WriteByte(u32, u32),
    WriteWord(u32, u32),
    WriteLong(u32, u32),
}
static mut musashi_memory:  [u8; 1024] = [0u8; 1024];
// as statics are not allowed to have destructors, allocate a
// big enough array to hold the small number of operations
// expected from executing a very limited number of opcodes
static mut musashi_opcount: usize = 0;
static mut musashi_ops: [Operation; 128] = [Operation::None; 128];

unsafe fn register_op(op: Operation) {
	if musashi_opcount < musashi_ops.len() {
		musashi_ops[musashi_opcount] = op;
		musashi_opcount += 1;
	}
}
// callbacks from Musashi
#[no_mangle]
pub extern fn cpu_read_byte(address: u32) -> u32 {
	let op = Operation::ReadByte(address);
	let address = address as usize;
	unsafe {
		register_op(op);
		musashi_memory[address] as u32
	}
}
#[no_mangle]
pub extern fn cpu_read_word(address: u32) -> u32 {
	let op = Operation::ReadWord(address);
	let address = address as usize;
	unsafe {
		register_op(op);
		((musashi_memory[address+0] as u32) << 8
		|(musashi_memory[address+1] as u32) << 0) as u32
	}
}
#[no_mangle]
pub extern fn cpu_read_long(address: u32) -> u32 {
	let op = Operation::ReadLong(address);
	let address = address as usize;
	unsafe {
		register_op(op);
		((musashi_memory[address+0] as u32) << 24
		|(musashi_memory[address+1] as u32) << 16
		|(musashi_memory[address+2] as u32) <<  8
		|(musashi_memory[address+3] as u32) <<  0) as u32
	}
}

#[no_mangle]
pub extern fn cpu_write_byte(address: u32, value: u32) {
	let op = Operation::WriteByte(address, value);
	let address = address as usize;
	unsafe {
		register_op(op);
		musashi_memory[address+0] = (value & 0xff) as u8;
	}
}
#[no_mangle]
pub extern fn cpu_write_word(address: u32, value: u32) {
	let op = Operation::WriteWord(address, value);
	let address = address as usize;
	unsafe {
		register_op(op);
		musashi_memory[address+0] = (value & 0xff00 >> 8) as u8;
		musashi_memory[address+1] = (value & 0x00ff >> 0) as u8;
	}
}
#[no_mangle]
pub extern fn cpu_write_long(address: u32, value: u32) {
	let op = Operation::WriteLong(address, value);
	let address = address as usize;
	unsafe {
		register_op(op);
		musashi_memory[address+0] = (value & 0xff000000 >> 24) as u8;
		musashi_memory[address+1] = (value & 0x00ff0000 >> 16) as u8;
		musashi_memory[address+2] = (value & 0x0000ff00 >>  8) as u8;
		musashi_memory[address+3] = (value & 0x000000ff >>  0) as u8;
	}
}

#[no_mangle]
pub extern fn cpu_pulse_reset() {panic!("pr")}
#[no_mangle]
pub extern fn cpu_long_branch() {}
#[no_mangle]
pub extern fn cpu_set_fc(fc: u32) {
	//println!("set_fc {}", fc)
}
#[no_mangle]
pub extern fn cpu_irq_ack(level: i32) -> i32 {panic!("ia")}
#[no_mangle]
pub extern fn cpu_instr_callback() {}

use std::ptr;

pub fn experimental_communication() {
	unsafe {
		m68k_init();
		m68k_set_cpu_type(CpuType::M68000);
		m68k_set_reg(Register::D0, 123);
		println!("D0: {}", m68k_get_reg(ptr::null_mut(), Register::D0));
	}
}

pub fn roundtrip_register(reg: Register, value: u32) -> u32 {
	unsafe {
		m68k_init();
		m68k_set_cpu_type(CpuType::M68000);
		m68k_set_reg(reg, value);
		m68k_get_reg(ptr::null_mut(), reg)
	}
}

use cpu::Core;

pub fn execute1(core: &mut Core) {
	unsafe {
		m68k_init();
		m68k_set_cpu_type(CpuType::M68000);
		m68k_pulse_reset();
		// Resetting opcount, because m68k_pulse_reset causes irrelevant
		// reads from 0x00000000 to set PC/SP, a jump to PC and
		// resetting of state. But we don't want to test those ops.
		musashi_opcount = 0;
		let regs = [Register::D0, Register::D1, Register::D2, Register::D3, Register::D4, Register::D5, Register::D6, Register::D7, Register::A0, Register::A1, Register::A2, Register::A3, Register::A4, Register::A5, Register::A6, Register::A7];
		m68k_set_reg(Register::PC, core.pc);
		m68k_set_reg(Register::SP, core.sp);
		m68k_set_reg(Register::SR, core.status_register());
		for (i, &reg) in regs.iter().enumerate() { m68k_set_reg(reg, core.dar[i]); }
		for (i,b) in core.mem.iter().enumerate() {
			musashi_memory[i] = *b;
		}
		m68k_execute(1);

		for (i, &reg) in regs.iter().enumerate() {
			core.dar[i] = m68k_get_reg(ptr::null_mut(), reg);
		}
		core.pc = m68k_get_reg(ptr::null_mut(), Register::PC);
		core.sp = m68k_get_reg(ptr::null_mut(), Register::SP);
		core.sr_to_flags(m68k_get_reg(ptr::null_mut(), Register::SR));
	}
}

#[cfg(test)]
mod tests {
	use super::*;
	use super::musashi_ops;
	use super::musashi_opcount;
	use super::Operation;
	use cpu::Core;

	fn get_ops() -> Vec<Operation> {
		let mut res: Vec<Operation> = vec![];
		unsafe {
			for i in 0..musashi_opcount {
				res.push(musashi_ops[i]);
			}
		}
		res
	}
	macro_rules! core_eq {
	    ($left:ident , $right:ident . $field:ident [ $index:expr ]) => ({
	        match (&($left.$field[$index]), &($right.$field[$index])) {
	            (left_val, right_val) => {
	                if !(*left_val == *right_val) {
	                    panic!("core coherence failed: `{}[{}]` differs)` \
	                           ({}: `{:?}`, {}: `{:?}`)", stringify!($field), $index, stringify!($left), left_val, stringify!($right), right_val)
	                }
	            }
	        }
	    });
	    ($left:ident , $right:ident . $field:ident () ) => ({
	        match (&($left.$field()), &($right.$field())) {
	            (left_val, right_val) => {
	                if !(*left_val == *right_val) {
	                    panic!("core coherence failed: `{}()` differs)` \
	                           ({}: `{:?}`, {}: `{:?}`)", stringify!($field), stringify!($left), left_val, stringify!($right), right_val)
	                }
	            }
	        }
	    });
	    ($left:ident , $right:ident . $field:ident) => ({
	        match (&($left.$field), &($right.$field)) {
	            (left_val, right_val) => {
	                if !(*left_val == *right_val) {
	                    panic!("core coherence failed: '{}' differs)` \
	                           ({}: `{:?}`, {}: `{:?}`)", stringify!($field), stringify!($left), left_val, stringify!($right), right_val)
	                }
	            }
	        }
	    })
	}
	fn assert_cores_equal(musashi: &Core, r68k: &Core, pc: u32) {
		core_eq!(musashi, r68k.pc);
		core_eq!(musashi, r68k.sp);
		for i in 0..16 {
			core_eq!(musashi, r68k.dar[i]);
		}
		core_eq!(musashi, r68k.flags());
		core_eq!(musashi, r68k.status_register());

		let ops = get_ops();
		assert_eq!(1, ops.len());
		assert_eq!(Operation::ReadLong(pc), ops[0]);
	}

	#[test]
	fn roundtrip_d0() {
		assert_eq!(256, roundtrip_register(Register::D0, 256));
	}

	#[test]
	fn roundtrip_abcd_rr() {
		let pc = 0x40;
		let mut cpu = Core::new_mem(pc, &[0xc3, 0x00]);
		cpu.dar[0] = 0x16;
		cpu.dar[1] = 0x26;
		execute1(&mut cpu);

		// 16 + 26 is 42
		assert_eq!(0x42, cpu.dar[1]);

		let ops = get_ops();
		assert_eq!(1, ops.len());
		assert_eq!(Operation::ReadLong(pc), ops[0]);
	}

	#[test]
	fn compare_abcd_rr() {
		let pc = 0x40;
		let mut musashi = Core::new_mem(pc, &[0xc3, 0x00]);
		musashi.dar[0] = 0x16;
		musashi.dar[1] = 0x26;

		let mut r68k = musashi.clone(); // so very self-aware!
		execute1(&mut musashi);
		r68k.execute1();

		assert_cores_equal(&musashi, &r68k, pc);
	}}<|endoftext|>


<commit_before>// Copyright 2016 Walter Kuppens.
//
// 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.

use io::log;
use nes::memory::Memory;
use nes::memory::MiscRegisterStatus;
use nes::memory::PPURegisterStatus;
use nes::nes::NESRuntimeOptions;

use nes::memory::{
    PPU_CTRL_REGISTERS_SIZE,
    MISC_CTRL_REGISTERS_SIZE,
};

const SPR_RAM_SIZE: usize = 0x00FF;

// Memory map section sizes.
const PATTERN_TABLES_SIZE: usize = 0x2000;
const NAME_TABLES_SIZE:    usize = 0x1000;
const PALETTES_SIZE:       usize = 0x0020;

// Memory map bounds.
const PATTERN_TABLES_START:     usize = 0x0000;
const PATTERN_TABLES_END:       usize = 0x1FFF;
const NAME_TABLES_START:        usize = 0x2000;
const NAME_TABLES_END:          usize = 0x2FFF;
const NAME_TABLES_MIRROR_START: usize = 0x3000;
const NAME_TABLES_MIRROR_END:   usize = 0x3EFF;
const PALETTES_START:           usize = 0x3F00;
const PALETTES_END:             usize = 0x3F1F;
const PALETTES_MIRROR_START:    usize = 0x3F20;
const PALETTES_MIRROR_END:      usize = 0x3FFF;
const MIRROR_START:             usize = 0x4000;
const MIRROR_END:               usize = 0xFFFF;

/// This is an implementation of the 2C02 PPU used in the NES. This piece of
/// hardware is responsible for drawing graphics to the television the console
/// is hooked up to; however in our case we draw to an SDL surface.
pub struct PPU {
    ppu_ctrl: u8,
    ppu_mask: u8,
    ppu_status: u8,

    // The runtime options contain some useful information such as television
    // standard which affect the clock rate of the PPU.
    runtime_options: NESRuntimeOptions,

    // The PPU has 2 pattern tables which store 8x8 pixel tiles which can be
    // drawn to the screen.
    pattern_tables: [u8; PATTERN_TABLES_SIZE],

    // The name tables are matrices of numbers that point to tiles stored in the
    // pattern tables. Each name table has an associated attribute table, which
    // contains the upper 2 bits of colors for each of the associated tiles.
    name_tables: [u8; NAME_TABLES_SIZE],

    // The PPU has 2 color palettes each containing 16 entires selected from the
    // PPU total selection of 52 colors. Because of this all possible colors the
    // PPU can create cannot be shown at once.
    //
    // Another thing to note is that the background color entry is mirrored
    // every 4 bytes so the effective number of color entries is reduced to 13
    // rather than 16.
    palettes: [u8; PALETTES_SIZE],

    // Where sprites are stored (different bus).
    spr_ram: [u8; SPR_RAM_SIZE],
}

impl PPU {
    /// Initializes the PPU and it's internal memory.
    pub fn new(runtime_options: NESRuntimeOptions) -> Self {
        PPU {
            ppu_ctrl: 0,
            ppu_mask: 0,
            ppu_status: 0,

            runtime_options: runtime_options,
            pattern_tables: [0; PATTERN_TABLES_SIZE],
            name_tables: [0; NAME_TABLES_SIZE],
            palettes: [0; PALETTES_SIZE],
            spr_ram: [0; SPR_RAM_SIZE],
        }
    }

    /// Maps a PPU virtual addresses to a physical address used internally by
    /// the PPU emulator.
    fn map(&mut self, addr: usize) -> (&mut [u8], usize) {
        match addr {
            PATTERN_TABLES_START...PATTERN_TABLES_END =>
                (&mut self.pattern_tables, addr),
            NAME_TABLES_START...NAME_TABLES_END =>
                (&mut self.name_tables, addr - NAME_TABLES_START),
            NAME_TABLES_MIRROR_START...NAME_TABLES_MIRROR_END =>
                (&mut self.name_tables, (addr - NAME_TABLES_START) % NAME_TABLES_SIZE),
            PALETTES_START...PALETTES_END =>
                (&mut self.palettes, addr - PALETTES_START),
            PALETTES_MIRROR_START...PALETTES_MIRROR_END =>
                (&mut self.palettes, (addr - PALETTES_START) % PALETTES_SIZE),
            MIRROR_START...MIRROR_END =>
                self.map(addr - MIRROR_START), // Lazy recursion to share nested mirror logic ^^^.
            _ => { panic!("Unable to map virtual address {:#X} to any physical address", addr) },
        }
    }

    /// Reads a byte from PPU memory at the given virtual address.
    fn read_u8(&mut self, addr: usize) -> u8 {
        let (bank, addr) = self.map(addr);
        bank[addr]
    }

    /// Writes a byte to PPU memory at the given virtual address.
    fn write_u8(&mut self, addr: usize, value: u8) {
        let (bank, addr) = self.map(addr);
        bank[addr] = value;
    }

    /// Copy data from main memory to the PPU's internal sprite memory.
    fn exec_dma(&mut self) {
    }

    /// Reads the contents of the DMA register and executes DMA if written since
    /// the last PPU cycle.
    ///
    /// TODO: Implement me!
    fn handle_dma_register<M: Memory>(&mut self, index: usize, state: MiscRegisterStatus, memory: &mut M) {
        if state != MiscRegisterStatus::Written {
            return;
        }
        let register = memory.misc_ctrl_registers()[index];
        println!("{:02X}", register);
        panic!("Implement DMA to continue!");
    }

    /// Updates the internal PPUCTRL register when the I/O register was written
    /// since the last PPU cycle.
    fn handle_ppu_ctrl<M: Memory>(&mut self, index: usize, state: PPURegisterStatus, memory: &mut M) {
        if state != PPURegisterStatus::Written {
            return;
        }
        self.ppu_ctrl = memory.ppu_ctrl_registers()[index];
        memory.ppu_ctrl_registers_status()[index] = PPURegisterStatus::Untouched;
    }

    /// Updates the internal PPUMASK register when the I/O register was written
    /// since the last PPU cycle.
    fn handle_ppu_mask<M: Memory>(&mut self, index: usize, state: PPURegisterStatus, memory: &mut M) {
        if state != PPURegisterStatus::Written {
            return;
        }
        self.ppu_mask = memory.ppu_ctrl_registers()[index];
        memory.ppu_ctrl_registers_status()[index] = PPURegisterStatus::Untouched;
    }

    /// Checks the status of PPU I/O registers and executes PPU functionality
    /// depending on their states.
    fn check_ppu_registers<M: Memory>(&mut self, memory: &mut M) {
        let mut io_registers_state = [PPURegisterStatus::Untouched; PPU_CTRL_REGISTERS_SIZE];
        io_registers_state.clone_from_slice(memory.ppu_ctrl_registers_status());

        for (index, state) in io_registers_state.iter().enumerate() {
            println!("PPU REGISTERS :: index: 0x{:02X}, state: {:?}", index, state);
            match index {
                0x00 => self.handle_ppu_ctrl(index, state.clone(), memory),
                0x01 => self.handle_ppu_mask(index, state.clone(), memory),
                _ => {
                    if state.clone() != PPURegisterStatus::Untouched {
                        panic!("Unsupported register modified");
                    }
                },
            }
        }
    }

    /// Checks the status of misc I/O registers and executes PPU functionality
    /// depending on their states.
    fn check_misc_registers<M: Memory>(&mut self, memory: &mut M) {
        let mut io_registers_state = [MiscRegisterStatus::Untouched; MISC_CTRL_REGISTERS_SIZE];
        io_registers_state.clone_from_slice(memory.misc_ctrl_registers_status());

        for (index, state) in io_registers_state.iter().enumerate() {
            println!("MISC REGISTERS :: index: 0x{:02X}, state: {:?}", index, state);
            match index {
                0x14 => self.handle_dma_register(index, state.clone(), memory),
                _ => {
                    if state.clone() != MiscRegisterStatus::Untouched {
                        panic!("Unsupported register modified");
                    }
                },
            };
        }
    }

    /// Executes routine PPU logic and returns stolen cycles from operations
    /// such as DMA transfers if the PPU hogged the main memory bus.
    pub fn execute<M: Memory>(&mut self, memory: &mut M) -> u16 {
        self.check_ppu_registers(memory);
        self.check_misc_registers(memory);

        log::log("ppu", "PPU cycle complete", &self.runtime_options);
        0
    }
}
<commit_msg>Removed some pointless log statements<commit_after>// Copyright 2016 Walter Kuppens.
//
// 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.

use io::log;
use nes::memory::Memory;
use nes::memory::MiscRegisterStatus;
use nes::memory::PPURegisterStatus;
use nes::nes::NESRuntimeOptions;

use nes::memory::{
    PPU_CTRL_REGISTERS_SIZE,
    MISC_CTRL_REGISTERS_SIZE,
};

const SPR_RAM_SIZE: usize = 0x00FF;

// Memory map section sizes.
const PATTERN_TABLES_SIZE: usize = 0x2000;
const NAME_TABLES_SIZE:    usize = 0x1000;
const PALETTES_SIZE:       usize = 0x0020;

// Memory map bounds.
const PATTERN_TABLES_START:     usize = 0x0000;
const PATTERN_TABLES_END:       usize = 0x1FFF;
const NAME_TABLES_START:        usize = 0x2000;
const NAME_TABLES_END:          usize = 0x2FFF;
const NAME_TABLES_MIRROR_START: usize = 0x3000;
const NAME_TABLES_MIRROR_END:   usize = 0x3EFF;
const PALETTES_START:           usize = 0x3F00;
const PALETTES_END:             usize = 0x3F1F;
const PALETTES_MIRROR_START:    usize = 0x3F20;
const PALETTES_MIRROR_END:      usize = 0x3FFF;
const MIRROR_START:             usize = 0x4000;
const MIRROR_END:               usize = 0xFFFF;

/// This is an implementation of the 2C02 PPU used in the NES. This piece of
/// hardware is responsible for drawing graphics to the television the console
/// is hooked up to; however in our case we draw to an SDL surface.
pub struct PPU {
    ppu_ctrl: u8,
    ppu_mask: u8,
    ppu_status: u8,

    // The runtime options contain some useful information such as television
    // standard which affect the clock rate of the PPU.
    runtime_options: NESRuntimeOptions,

    // The PPU has 2 pattern tables which store 8x8 pixel tiles which can be
    // drawn to the screen.
    pattern_tables: [u8; PATTERN_TABLES_SIZE],

    // The name tables are matrices of numbers that point to tiles stored in the
    // pattern tables. Each name table has an associated attribute table, which
    // contains the upper 2 bits of colors for each of the associated tiles.
    name_tables: [u8; NAME_TABLES_SIZE],

    // The PPU has 2 color palettes each containing 16 entires selected from the
    // PPU total selection of 52 colors. Because of this all possible colors the
    // PPU can create cannot be shown at once.
    //
    // Another thing to note is that the background color entry is mirrored
    // every 4 bytes so the effective number of color entries is reduced to 13
    // rather than 16.
    palettes: [u8; PALETTES_SIZE],

    // Where sprites are stored (different bus).
    spr_ram: [u8; SPR_RAM_SIZE],
}

impl PPU {
    /// Initializes the PPU and it's internal memory.
    pub fn new(runtime_options: NESRuntimeOptions) -> Self {
        PPU {
            ppu_ctrl: 0,
            ppu_mask: 0,
            ppu_status: 0,

            runtime_options: runtime_options,
            pattern_tables: [0; PATTERN_TABLES_SIZE],
            name_tables: [0; NAME_TABLES_SIZE],
            palettes: [0; PALETTES_SIZE],
            spr_ram: [0; SPR_RAM_SIZE],
        }
    }

    /// Maps a PPU virtual addresses to a physical address used internally by
    /// the PPU emulator.
    fn map(&mut self, addr: usize) -> (&mut [u8], usize) {
        match addr {
            PATTERN_TABLES_START...PATTERN_TABLES_END =>
                (&mut self.pattern_tables, addr),
            NAME_TABLES_START...NAME_TABLES_END =>
                (&mut self.name_tables, addr - NAME_TABLES_START),
            NAME_TABLES_MIRROR_START...NAME_TABLES_MIRROR_END =>
                (&mut self.name_tables, (addr - NAME_TABLES_START) % NAME_TABLES_SIZE),
            PALETTES_START...PALETTES_END =>
                (&mut self.palettes, addr - PALETTES_START),
            PALETTES_MIRROR_START...PALETTES_MIRROR_END =>
                (&mut self.palettes, (addr - PALETTES_START) % PALETTES_SIZE),
            MIRROR_START...MIRROR_END =>
                self.map(addr - MIRROR_START), // Lazy recursion to share nested mirror logic ^^^.
            _ => { panic!("Unable to map virtual address {:#X} to any physical address", addr) },
        }
    }

    /// Reads a byte from PPU memory at the given virtual address.
    fn read_u8(&mut self, addr: usize) -> u8 {
        let (bank, addr) = self.map(addr);
        bank[addr]
    }

    /// Writes a byte to PPU memory at the given virtual address.
    fn write_u8(&mut self, addr: usize, value: u8) {
        let (bank, addr) = self.map(addr);
        bank[addr] = value;
    }

    /// Copy data from main memory to the PPU's internal sprite memory.
    fn exec_dma(&mut self) {
    }

    /// Reads the contents of the DMA register and executes DMA if written since
    /// the last PPU cycle.
    ///
    /// TODO: Implement me!
    fn handle_dma_register<M: Memory>(&mut self, index: usize, state: MiscRegisterStatus, memory: &mut M) {
        if state != MiscRegisterStatus::Written {
            return;
        }
        let register = memory.misc_ctrl_registers()[index];
        println!("{:02X}", register);
        panic!("Implement DMA to continue!");
    }

    /// Updates the internal PPUCTRL register when the I/O register was written
    /// since the last PPU cycle.
    fn handle_ppu_ctrl<M: Memory>(&mut self, index: usize, state: PPURegisterStatus, memory: &mut M) {
        if state != PPURegisterStatus::Written {
            return;
        }
        self.ppu_ctrl = memory.ppu_ctrl_registers()[index];
        memory.ppu_ctrl_registers_status()[index] = PPURegisterStatus::Untouched;
    }

    /// Updates the internal PPUMASK register when the I/O register was written
    /// since the last PPU cycle.
    fn handle_ppu_mask<M: Memory>(&mut self, index: usize, state: PPURegisterStatus, memory: &mut M) {
        if state != PPURegisterStatus::Written {
            return;
        }
        self.ppu_mask = memory.ppu_ctrl_registers()[index];
        memory.ppu_ctrl_registers_status()[index] = PPURegisterStatus::Untouched;
    }

    /// Checks the status of PPU I/O registers and executes PPU functionality
    /// depending on their states.
    fn check_ppu_registers<M: Memory>(&mut self, memory: &mut M) {
        let mut io_registers_state = [PPURegisterStatus::Untouched; PPU_CTRL_REGISTERS_SIZE];
        io_registers_state.clone_from_slice(memory.ppu_ctrl_registers_status());

        for (index, state) in io_registers_state.iter().enumerate() {
            match index {
                0x00 => self.handle_ppu_ctrl(index, state.clone(), memory),
                0x01 => self.handle_ppu_mask(index, state.clone(), memory),
                _ => {
                    if state.clone() != PPURegisterStatus::Untouched {
                        panic!("Unsupported ppu register touched: 0x{:02X}", index);
                    }
                },
            }
        }
    }

    /// Checks the status of misc I/O registers and executes PPU functionality
    /// depending on their states.
    fn check_misc_registers<M: Memory>(&mut self, memory: &mut M) {
        let mut io_registers_state = [MiscRegisterStatus::Untouched; MISC_CTRL_REGISTERS_SIZE];
        io_registers_state.clone_from_slice(memory.misc_ctrl_registers_status());

        for (index, state) in io_registers_state.iter().enumerate() {
            match index {
                0x14 => self.handle_dma_register(index, state.clone(), memory),
                _ => {
                    if state.clone() != MiscRegisterStatus::Untouched {
                        panic!("Unsupported misc register touched: 0x{:02X}", index);
                    }
                },
            };
        }
    }

    /// Executes routine PPU logic and returns stolen cycles from operations
    /// such as DMA transfers if the PPU hogged the main memory bus.
    pub fn execute<M: Memory>(&mut self, memory: &mut M) -> u16 {
        self.check_ppu_registers(memory);
        self.check_misc_registers(memory);
        0
    }
}
<|endoftext|>


<commit_before><commit_msg>Newline is now trimmed off of user input<commit_after><|endoftext|>


<commit_before><commit_msg>Introduce word dictionary<commit_after><|endoftext|>


<commit_before><commit_msg>Added more Vector API.<commit_after><|endoftext|>


<commit_before>use std::io;
use std::net::{IpAddr, SocketAddr, UdpSocket, Ipv4Addr};

use request::RequestBin;
use response;
use response::Response;

pub struct Network {}

/// Represents a device on the network, as well as a response.
pub struct Device {
    pub socket_addr: SocketAddr,
    pub response: Option<Response>,
}

impl Network {
    pub fn send_discover_devices(msg_bin: RequestBin) -> Result<Device, io::Error> {
        let use_broadcast = true;
        let broadcast_ip = IpAddr::V4(Ipv4Addr::new(192, 168, 0, 0));
        let broadcast_port = 56700;
        let broadcast_sock_addr = SocketAddr::new(broadcast_ip, broadcast_port);

        send(msg_bin, use_broadcast, broadcast_sock_addr)
    }
}

impl Device {
    pub fn send_get_device_power_state(&self, msg_bin: RequestBin) -> Result<Device, io::Error> {
        let use_broadcast = false;

        send(msg_bin, use_broadcast, self.socket_addr)
    }

    pub fn send_set_device_power_state(&self, msg_bin: RequestBin) -> Result<Device, io::Error> {
        let use_broadcast = false;

        send(msg_bin, use_broadcast, self.socket_addr)
    }

    pub fn send_get_device_state(&self, msg_bin: RequestBin) -> Result<Device, io::Error> {
        let use_broadcast = false;

        send(msg_bin, use_broadcast, self.socket_addr)
    }

    pub fn send_set_device_state(&self, msg_bin: RequestBin) -> Result<Device, io::Error> {
        let use_broadcast = false;

        send(msg_bin, use_broadcast, self.socket_addr)
    }
}

fn send(msg_bin: RequestBin,
        broadcast: bool,
        device_socket_addr: SocketAddr)
        -> Result<Device, io::Error> {
    let local_ip = IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0));
    let local_sock_addr = SocketAddr::new(local_ip, 56700);
    let local_sock = try!(UdpSocket::bind(local_sock_addr));
    local_sock.set_broadcast(broadcast)?;

    let msg = &msg_bin.0;
    display(msg);
    try!(local_sock.send_to(&msg, device_socket_addr));

    // Read from the socket
    let mut resp_buf = [0; 1024];
    let (sz, src_sock_addr) = try!(local_sock.recv_from(&mut resp_buf));

    let resp_msg = &resp_buf[0..sz];
    println!("Received from {} : \n{:?}", src_sock_addr, resp_msg);

    let resp = response::parse_response(response::ResponseData(resp_msg.to_vec()));
    // let resp = response::parse_response(response::ResponseMessage(resp_msg.to_vec()));

    let device = Device {
        socket_addr: src_sock_addr,
        response: Some(resp),
    };

    Ok(device)
}

fn display(msg_bin: &Vec<u8>) {
    println!("---- Sending request: ----");
    println!("Dec: {:?}", msg_bin);
    print!("Bytes: ");
    for b in msg_bin.iter() {
        print!("{:x} ", b);
    }
    println!("\n----");
}
<commit_msg>Add timeouts.<commit_after>use std::io;
use std::time::Duration;
use std::net::{IpAddr, SocketAddr, UdpSocket, Ipv4Addr};

use request::RequestBin;
use response;
use response::Response;

pub struct Network {}

/// Represents a device on the network, as well as a response.
pub struct Device {
    pub socket_addr: SocketAddr,
    pub response: Option<Response>,
}

impl Network {
    pub fn send_discover_devices(msg_bin: RequestBin) -> Result<Device, io::Error> {
        let use_broadcast = true;
        let broadcast_ip = IpAddr::V4(Ipv4Addr::new(192, 168, 0, 0));
        let broadcast_port = 56700;
        let broadcast_sock_addr = SocketAddr::new(broadcast_ip, broadcast_port);

        send(msg_bin, use_broadcast, broadcast_sock_addr)
    }
}

impl Device {
    pub fn send_get_device_power_state(&self, msg_bin: RequestBin) -> Result<Device, io::Error> {
        let use_broadcast = false;

        send(msg_bin, use_broadcast, self.socket_addr)
    }

    pub fn send_set_device_power_state(&self, msg_bin: RequestBin) -> Result<Device, io::Error> {
        let use_broadcast = false;

        send(msg_bin, use_broadcast, self.socket_addr)
    }

    pub fn send_get_device_state(&self, msg_bin: RequestBin) -> Result<Device, io::Error> {
        let use_broadcast = false;

        send(msg_bin, use_broadcast, self.socket_addr)
    }

    pub fn send_set_device_state(&self, msg_bin: RequestBin) -> Result<Device, io::Error> {
        let use_broadcast = false;

        send(msg_bin, use_broadcast, self.socket_addr)
    }
}

fn send(msg_bin: RequestBin,
        broadcast: bool,
        device_socket_addr: SocketAddr)
        -> Result<Device, io::Error> {
    let local_ip = IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0));
    let local_sock_addr = SocketAddr::new(local_ip, 56700);
    let local_sock = try!(UdpSocket::bind(local_sock_addr));
    let _ = local_sock.set_write_timeout(Some(Duration::new(3, 0)));
    let _ = local_sock.set_read_timeout(Some(Duration::new(3, 0)));
    local_sock.set_broadcast(broadcast)?;

    let msg = &msg_bin.0;
    display(msg);
    try!(local_sock.send_to(&msg, device_socket_addr));

    // Read from the socket
    let mut resp_buf = [0; 1024];
    let (sz, src_sock_addr) = try!(local_sock.recv_from(&mut resp_buf));

    let resp_msg = &resp_buf[0..sz];
    println!("Received from {} : \n{:?}", src_sock_addr, resp_msg);

    let resp = response::parse_response(response::ResponseData(resp_msg.to_vec()));
    // let resp = response::parse_response(response::ResponseMessage(resp_msg.to_vec()));

    let device = Device {
        socket_addr: src_sock_addr,
        response: Some(resp),
    };

    Ok(device)
}

fn display(msg_bin: &Vec<u8>) {
    println!("---- Sending request: ----");
    println!("Dec: {:?}", msg_bin);
    print!("Bytes: ");
    for b in msg_bin.iter() {
        print!("{:x} ", b);
    }
    println!("\n----");
}
<|endoftext|>


<commit_before>use std::fs::File;
use std::io::{Read, Write};
use std::os::unix::io::{IntoRawFd, AsRawFd, FromRawFd, RawFd};

use libc;

use {io, Ready, Poll, PollOpt, Token};
use event::Evented;
use unix::EventedFd;
use sys::unix::cvt;

pub fn set_nonblock(fd: libc::c_int) -> io::Result<()> {
    unsafe {
        let flags = libc::fcntl(fd, libc::F_GETFL);
        cvt(libc::fcntl(fd, libc::F_SETFL, flags | libc::O_NONBLOCK)).map(|_|())
    }
}

pub fn set_cloexec(fd: libc::c_int) -> io::Result<()> {
    unsafe {
        let flags = libc::fcntl(fd, libc::F_GETFL);
        cvt(libc::fcntl(fd, libc::F_SETFL, flags | libc::O_CLOEXEC)).map(|_| ())
    }
}

/*
 *
 * ===== Basic IO type =====
 *
 */

/// Manages a FD
#[derive(Debug)]
pub struct Io {
    fd: File,
}

impl Io {
    /// Try to clone the FD
    pub fn try_clone(&self) -> io::Result<Io> {
        Ok(Io { fd: try!(self.fd.try_clone()) })
    }
}

impl FromRawFd for Io {
    unsafe fn from_raw_fd(fd: RawFd) -> Io {
        Io { fd: File::from_raw_fd(fd) }
    }
}

impl IntoRawFd for Io {
    fn into_raw_fd(self) -> RawFd {
        self.fd.into_raw_fd()
    }
}

impl AsRawFd for Io {
    fn as_raw_fd(&self) -> RawFd {
        self.fd.as_raw_fd()
    }
}

impl Evented for Io {
    fn register(&self, poll: &Poll, token: Token, interest: Ready, opts: PollOpt) -> io::Result<()> {
        EventedFd(&self.as_raw_fd()).register(poll, token, interest, opts)
    }

    fn reregister(&self, poll: &Poll, token: Token, interest: Ready, opts: PollOpt) -> io::Result<()> {
        EventedFd(&self.as_raw_fd()).reregister(poll, token, interest, opts)
    }

    fn deregister(&self, poll: &Poll) -> io::Result<()> {
        EventedFd(&self.as_raw_fd()).deregister(poll)
    }
}

impl Read for Io {
    fn read(&mut self, dst: &mut [u8]) -> io::Result<usize> {
        (&self.fd).read(dst)
    }
}

impl<'a> Read for &'a Io {
    fn read(&mut self, dst: &mut [u8]) -> io::Result<usize> {
        (&self.fd).read(dst)
    }
}

impl Write for Io {
    fn write(&mut self, src: &[u8]) -> io::Result<usize> {
        (&self.fd).write(src)
    }

    fn flush(&mut self) -> io::Result<()> {
        (&self.fd).flush()
    }
}

impl<'a> Write for &'a Io {
    fn write(&mut self, src: &[u8]) -> io::Result<usize> {
        (&self.fd).write(src)
    }

    fn flush(&mut self) -> io::Result<()> {
        (&self.fd).flush()
    }
}
<commit_msg>Fix usage of O_CLOEXEC in SETFL (#596)<commit_after>use std::fs::File;
use std::io::{Read, Write};
use std::os::unix::io::{IntoRawFd, AsRawFd, FromRawFd, RawFd};

use libc;

use {io, Ready, Poll, PollOpt, Token};
use event::Evented;
use unix::EventedFd;
use sys::unix::cvt;

pub fn set_nonblock(fd: libc::c_int) -> io::Result<()> {
    unsafe {
        let flags = libc::fcntl(fd, libc::F_GETFL);
        cvt(libc::fcntl(fd, libc::F_SETFL, flags | libc::O_NONBLOCK)).map(|_|())
    }
}

pub fn set_cloexec(fd: libc::c_int) -> io::Result<()> {
    unsafe {
        let flags = libc::fcntl(fd, libc::F_GETFD);
        cvt(libc::fcntl(fd, libc::F_SETFD, flags | libc::FD_CLOEXEC)).map(|_| ())
    }
}

/*
 *
 * ===== Basic IO type =====
 *
 */

/// Manages a FD
#[derive(Debug)]
pub struct Io {
    fd: File,
}

impl Io {
    /// Try to clone the FD
    pub fn try_clone(&self) -> io::Result<Io> {
        Ok(Io { fd: try!(self.fd.try_clone()) })
    }
}

impl FromRawFd for Io {
    unsafe fn from_raw_fd(fd: RawFd) -> Io {
        Io { fd: File::from_raw_fd(fd) }
    }
}

impl IntoRawFd for Io {
    fn into_raw_fd(self) -> RawFd {
        self.fd.into_raw_fd()
    }
}

impl AsRawFd for Io {
    fn as_raw_fd(&self) -> RawFd {
        self.fd.as_raw_fd()
    }
}

impl Evented for Io {
    fn register(&self, poll: &Poll, token: Token, interest: Ready, opts: PollOpt) -> io::Result<()> {
        EventedFd(&self.as_raw_fd()).register(poll, token, interest, opts)
    }

    fn reregister(&self, poll: &Poll, token: Token, interest: Ready, opts: PollOpt) -> io::Result<()> {
        EventedFd(&self.as_raw_fd()).reregister(poll, token, interest, opts)
    }

    fn deregister(&self, poll: &Poll) -> io::Result<()> {
        EventedFd(&self.as_raw_fd()).deregister(poll)
    }
}

impl Read for Io {
    fn read(&mut self, dst: &mut [u8]) -> io::Result<usize> {
        (&self.fd).read(dst)
    }
}

impl<'a> Read for &'a Io {
    fn read(&mut self, dst: &mut [u8]) -> io::Result<usize> {
        (&self.fd).read(dst)
    }
}

impl Write for Io {
    fn write(&mut self, src: &[u8]) -> io::Result<usize> {
        (&self.fd).write(src)
    }

    fn flush(&mut self) -> io::Result<()> {
        (&self.fd).flush()
    }
}

impl<'a> Write for &'a Io {
    fn write(&mut self, src: &[u8]) -> io::Result<usize> {
        (&self.fd).write(src)
    }

    fn flush(&mut self) -> io::Result<()> {
        (&self.fd).flush()
    }
}
<|endoftext|>


<commit_before>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.

// revisions: rpass1 rpass2
// compile-flags: -Z query-dep-graph

#![allow(warnings)]
#![feature(rustc_attrs)]

fn main() { }

mod x {
    #[cfg(rpass1)]
    pub fn x() -> i32 {
        1
    }

    #[cfg(rpass2)]
    pub fn x() -> i32 {
        2
    }
}

mod y {
    use x;

    #[rustc_clean(label="TypeckItemBody", cfg="rpass2")]
    pub fn y() {
        x::x();
    }
}

mod z {
    use y;

    #[rustc_clean(label="TypeckItemBody", cfg="rpass2")]
    pub fn z() {
        y::y();
    }
}
<commit_msg>Make hello_world test work again<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.

// revisions: rpass1 rpass2
// compile-flags: -Z query-dep-graph

#![allow(warnings)]
#![feature(rustc_attrs)]

fn main() { }

mod x {
    #[cfg(rpass1)]
    pub fn xxxx() -> i32 {
        1
    }

    #[cfg(rpass2)]
    pub fn xxxx() -> i32 {
        2
    }
}

mod y {
    use x;

    // FIXME: This should be clean
    #[rustc_dirty(label="TypeckItemBody", cfg="rpass2")]
    pub fn yyyy() {
        x::xxxx();
    }
}

mod z {
    use y;

    #[rustc_clean(label="TypeckItemBody", cfg="rpass2")]
    pub fn z() {
        y::yyyy();
    }
}
<|endoftext|>