forked from pcwalton/sprocketnes
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmem.rs
143 lines (125 loc) · 3.38 KB
/
mem.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
//
// sprocketnes/mem.rs
//
// Author: Patrick Walton
//
use apu::Apu;
use input::Input;
use mapper::Mapper;
use ppu::Ppu;
use util::Save;
use std::cell::RefCell;
use std::io::File;
use std::rc::Rc;
//
// The memory interface
//
/// The basic memory interface
pub trait Mem {
fn loadb(&mut self, addr: u16) -> u8;
fn storeb(&mut self, addr: u16, val: u8);
}
pub trait MemUtil {
fn loadw(&mut self, addr: u16) -> u16;
fn storew(&mut self, addr: u16, val: u16);
fn loadw_zp(&mut self, addr: u8) -> u16;
}
impl<M:Mem> MemUtil for M {
fn loadw(&mut self, addr: u16) -> u16 {
self.loadb(addr) as u16 | (self.loadb(addr + 1) as u16 << 8)
}
fn storew(&mut self, addr: u16, val: u16) {
self.storeb(addr, (val & 0xff) as u8);
self.storeb(addr + 1, ((val >> 8) & 0xff) as u8);
}
// Like loadw, but has wraparound behavior on the zero page for address 0xff.
fn loadw_zp(&mut self, addr: u8) -> u16 {
self.loadb(addr as u16) as u16 | (self.loadb((addr + 1) as u16) as u16 << 8)
}
}
//
// The NES' paltry 2KB of RAM
//
pub struct Ram { pub val: [u8, ..0x800] }
impl Deref<[u8, ..0x800]> for Ram {
fn deref<'a>(&'a self) -> &'a [u8, ..0x800] {
&self.val
}
}
impl DerefMut<[u8, ..0x800]> for Ram {
fn deref_mut<'a>(&'a mut self) -> &'a mut [u8, ..0x800] {
&mut self.val
}
}
impl Mem for Ram {
fn loadb(&mut self, addr: u16) -> u8 { self[addr as uint & 0x7ff] }
fn storeb(&mut self, addr: u16, val: u8) { self[addr as uint & 0x7ff] = val }
}
impl Save for Ram {
fn save(&mut self, fd: &mut File) {
(*self).as_mut_slice().save(fd);
}
fn load(&mut self, fd: &mut File) {
(*self).as_mut_slice().load(fd);
}
}
//
// The main CPU memory map
//
pub struct MemMap {
pub ram: Ram,
pub ppu: Ppu,
pub input: Input,
pub mapper: Rc<RefCell<~Mapper:Send>>,
pub apu: Apu,
}
impl MemMap {
pub fn new(ppu: Ppu,
input: Input,
mapper: Rc<RefCell<~Mapper:Send>>,
apu: Apu)
-> MemMap {
MemMap {
ram: Ram{val: [ 0u8, ..0x800 ]},
ppu: ppu,
input: input,
mapper: mapper,
apu: apu,
}
}
}
impl Mem for MemMap {
fn loadb(&mut self, addr: u16) -> u8 {
if addr < 0x2000 {
self.ram.loadb(addr)
} else if addr < 0x4000 {
self.ppu.loadb(addr)
} else if addr == 0x4016 {
self.input.loadb(addr)
} else if addr <= 0x4018 {
self.apu.loadb(addr)
} else if addr < 0x6000 {
0 // FIXME: I think some mappers use regs in this area?
} else {
let mut mapper = self.mapper.borrow_mut();
mapper.prg_loadb(addr)
}
}
fn storeb(&mut self, addr: u16, val: u8) {
if addr < 0x2000 {
self.ram.storeb(addr, val)
} else if addr < 0x4000 {
self.ppu.storeb(addr, val)
} else if addr == 0x4016 {
self.input.storeb(addr, val)
} else if addr <= 0x4018 {
self.apu.storeb(addr, val)
} else if addr < 0x6000 {
// Nothing. FIXME: I think some mappers use regs in this area?
} else {
let mut mapper = self.mapper.borrow_mut();
mapper.prg_storeb(addr, val)
}
}
}
save_struct!(MemMap { ram, ppu, apu })