<commit_before>//! Input/Output abstraction for memory, ROM and I/O mapped registers

use gpu::Gpu;

pub mod rom;
pub mod ram;
pub mod timer;

/// Interconnect struct used by the CPU and GPU to access the ROM, RAM
/// and registers
pub struct Interconnect<'a> {
    rom:        rom::Rom,
    /// Bankable RAM
    ram:        ram::Ram,
    /// internal RAM
    iram:       ram::Ram,
    /// 0-page RAM
    zpage:      ram::Ram,
    /// Timer instance
    timer:      timer::Timer,
    /// GPU instance
    gpu:        Gpu<'a>,
    /// Used to store the value of IO Port when not properly
    /// implemented.
    io:         [u8, ..0x4c],
    /// Enabled interrupts
    it_enabled: Interrupts,
    /// Current DMA source address
    dma_src:    u16,
    /// Current DMA index in OAM
    dma_idx:    u16,
}

impl<'a> Interconnect<'a> {
    /// Create a new Interconnect
    pub fn new<'n>(rom: rom::Rom, gpu: Gpu<'n>) -> Interconnect<'n> {

        let ram = ram::Ram::new(0x2000);
        let iram = ram::Ram::new(0x2000);
        let zpage = ram::Ram::new(0x7f);
        let io = [0, ..0x4c];

        let timer = timer::Timer::new();

        let it_enabled = Interrupts::from_register(0);

        Interconnect { rom:        rom,
                       ram:        ram,
                       iram:       iram,
                       zpage:      zpage,
                       timer:      timer,
                       gpu:        gpu,
                       io:         io,
                       it_enabled: it_enabled,
                       dma_src:    0,
                       dma_idx:    map::range_size(map::OAM),
        }
    }

    pub fn reset(&mut self) {
        self.ram.reset();
        self.iram.reset();
        self.gpu.reset();
        self.zpage.reset();

        self.timer.reset();

        self.it_enabled = Interrupts::from_register(0);

        self.dma_src = 0;
        self.dma_idx = map::range_size(map::OAM);

        for b in self.io.iter_mut() {
            *b = 0;
        }
    }

    pub fn step(&mut self) {
        self.gpu.step();
        self.dma_step();
        self.timer.step();
    }

    pub fn dma_step(&mut self) {
        let end = map::range_size(map::OAM);

        if self.dma_idx >= end {
            // No dma transfer in progress
            return;
        }

        let b = self.get_byte(self.dma_src);
        self.gpu.set_oam(self.dma_idx, b);

        self.dma_src += 1;
        self.dma_idx += 1;
    }

    /// Get byte from peripheral mapped at `addr`
    pub fn get_byte(&self, addr: u16) -> u8 {

        if let Some(off) = map::in_range(addr, map::ROM) {
            return self.rom.get_byte(off);
        }

        if let Some(off) = map::in_range(addr, map::VRAM) {
            return self.gpu.get_vram(off);
        }

        if let Some(off) = map::in_range(addr, map::RAM_BANK) {
            return self.ram.get_byte(off);
        }

        if let Some(off) = map::in_range(addr, map::IRAM) {
            return self.iram.get_byte(off);
        }

        if let Some(off) = map::in_range(addr, map::IRAM_ECHO) {
            return self.iram.get_byte(off);
        }

        if let Some(off) = map::in_range(addr, map::OAM) {
            return self.gpu.get_oam(off);
        }

        if let Some(off) = map::in_range(addr, map::IO) {
            return self.get_io(off);
        }

        if let Some(off) = map::in_range(addr, map::ZERO_PAGE) {
            return self.zpage.get_byte(off);
        }

        if addr == map::IEN {
            return self.it_enabled.as_register();
        }

        println!("Read from unmapped memory {:04x}", addr);
        0
    }

    /// Store `val` into peripheral mapped at `addr`
    pub fn set_byte(&mut self, addr: u16, val: u8) {
        if let Some(_) = map::in_range(addr, map::ROM) {
            println!("Writing to ROM: {:04x}: {:02x}", addr, val);
        }

        if let Some(off) = map::in_range(addr, map::VRAM) {
            return self.gpu.set_vram(off, val);<commit_msg>Fix bogus message when writing to ROM<commit_after>//! Input/Output abstraction for memory, ROM and I/O mapped registers

use gpu::Gpu;

pub mod rom;
pub mod ram;
pub mod timer;

/// Interconnect struct used by the CPU and GPU to access the ROM, RAM
/// and registers
pub struct Interconnect<'a> {
    rom:        rom::Rom,
    /// Bankable RAM
    ram:        ram::Ram,
    /// internal RAM
    iram:       ram::Ram,
    /// 0-page RAM
    zpage:      ram::Ram,
    /// Timer instance
    timer:      timer::Timer,
    /// GPU instance
    gpu:        Gpu<'a>,
    /// Used to store the value of IO Port when not properly
    /// implemented.
    io:         [u8, ..0x4c],
    /// Enabled interrupts
    it_enabled: Interrupts,
    /// Current DMA source address
    dma_src:    u16,
    /// Current DMA index in OAM
    dma_idx:    u16,
}

impl<'a> Interconnect<'a> {
    /// Create a new Interconnect
    pub fn new<'n>(rom: rom::Rom, gpu: Gpu<'n>) -> Interconnect<'n> {

        let ram = ram::Ram::new(0x2000);
        let iram = ram::Ram::new(0x2000);
        let zpage = ram::Ram::new(0x7f);
        let io = [0, ..0x4c];

        let timer = timer::Timer::new();

        let it_enabled = Interrupts::from_register(0);

        Interconnect { rom:        rom,
                       ram:        ram,
                       iram:       iram,
                       zpage:      zpage,
                       timer:      timer,
                       gpu:        gpu,
                       io:         io,
                       it_enabled: it_enabled,
                       dma_src:    0,
                       dma_idx:    map::range_size(map::OAM),
        }
    }

    pub fn reset(&mut self) {
        self.ram.reset();
        self.iram.reset();
        self.gpu.reset();
        self.zpage.reset();

        self.timer.reset();

        self.it_enabled = Interrupts::from_register(0);

        self.dma_src = 0;
        self.dma_idx = map::range_size(map::OAM);

        for b in self.io.iter_mut() {
            *b = 0;
        }
    }

    pub fn step(&mut self) {
        self.gpu.step();
        self.dma_step();
        self.timer.step();
    }

    pub fn dma_step(&mut self) {
        let end = map::range_size(map::OAM);

        if self.dma_idx >= end {
            // No dma transfer in progress
            return;
        }

        let b = self.get_byte(self.dma_src);
        self.gpu.set_oam(self.dma_idx, b);

        self.dma_src += 1;
        self.dma_idx += 1;
    }

    /// Get byte from peripheral mapped at `addr`
    pub fn get_byte(&self, addr: u16) -> u8 {

        if let Some(off) = map::in_range(addr, map::ROM) {
            return self.rom.get_byte(off);
        }

        if let Some(off) = map::in_range(addr, map::VRAM) {
            return self.gpu.get_vram(off);
        }

        if let Some(off) = map::in_range(addr, map::RAM_BANK) {
            return self.ram.get_byte(off);
        }

        if let Some(off) = map::in_range(addr, map::IRAM) {
            return self.iram.get_byte(off);
        }

        if let Some(off) = map::in_range(addr, map::IRAM_ECHO) {
            return self.iram.get_byte(off);
        }

        if let Some(off) = map::in_range(addr, map::OAM) {
            return self.gpu.get_oam(off);
        }

        if let Some(off) = map::in_range(addr, map::IO) {
            return self.get_io(off);
        }

        if let Some(off) = map::in_range(addr, map::ZERO_PAGE) {
            return self.zpage.get_byte(off);
        }

        if addr == map::IEN {
            return self.it_enabled.as_register();
        }

        println!("Read from unmapped memory {:04x}", addr);
        0
    }

    /// Store `val` into peripheral mapped at `addr`
    pub fn set_byte(&mut self, addr: u16, val: u8) {
        if let Some(_) = map::in_range(addr, map::ROM) {
            println!("Writing to ROM: {:04x}: {:02x}", addr, val);
            return;
        }

        if let Some(off) = map::in_range(addr, map::VRAM) {
            return self.gpu.set_vram(off, val);
{'fraction_non_alphanumeric': 0.13631853138179112, 'fraction_numerical': 0.010667328206400397, 'mean_word_length': 1.5727504786215698, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 23, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1247766', 'n_tokens_mistral': 2751, 'n_tokens_neox': 2597, 'n_words': 636}