Skip to main content

gb_cpu_sim/
reg.rs

1use try_from_discrim::TryFrom;
2
3#[derive(Debug, TryFrom, Clone, Copy)]
4#[from(u16)]
5#[non_exhaustive]
6/// A collection of hardware registers' addresses, extracted from [`hardware.inc`](https://github.com/gbdev/hardware.inc).
7pub enum HwReg {
8	/// MBC SRAM enable.
9	Ramg = 0x0000,
10	/// MBC ROM bank switch, low 8 bits.
11	Romb0 = 0x2000,
12	/// MBC ROM bank switch, upper 8 bits.
13	Romb1 = 0x3000,
14	/// MBC SRAM bank switch.
15	Ramb = 0x4000,
16	/// MBC RTC latch toggle.
17	Rtclatch = 0x6000,
18
19	/// Joypad.
20	P1 = 0xFF00,
21
22	/// Serial data.
23	Sb = 0xFF01,
24	/// Serial control.
25	Sc = 0xFF02,
26
27	/// Divided clock counter.
28	Div = 0xFF04,
29	/// Timer counter.
30	Tima = 0xFF05,
31	/// Timer modulo.
32	Tma = 0xFF06,
33	/// Timer control.
34	Tac = 0xFF07,
35
36	/// Pending interrupts.
37	If = 0xFF0F,
38
39	/// CH1 frequency sweep.
40	Nr10 = 0xFF10,
41	/// CH1 duty control & sound length.
42	Nr11 = 0xFF11,
43	/// CH1 volume control.
44	Nr12 = 0xFF12,
45	/// CH1 wave_length, low 8 bits.
46	Nr13 = 0xFF13,
47	/// CH1 wave_length, upper 3 bits & control.
48	Nr14 = 0xFF14,
49	/// CH2 duty control & sound length.
50	Nr21 = 0xFF16,
51	/// CH2 volume control.
52	Nr22 = 0xFF17,
53	/// CH2 wave_length, low 8 bits.
54	Nr23 = 0xFF18,
55	/// CH2 wave_length, upper 3 bits & control.
56	Nr24 = 0xFF19,
57	/// CH3 enable.
58	Nr30 = 0xFF1A,
59	/// CH3 sound length.
60	Nr31 = 0xFF1B,
61	/// CH3 volume control.
62	Nr32 = 0xFF1C,
63	/// CH3 wave_length, low 8 bits.
64	Nr33 = 0xFF1D,
65	/// CH3 wave_length, upper 3 bits.
66	Nr34 = 0xFF1E,
67	/// CH4 sound length.
68	Nr41 = 0xFF20,
69	/// CH4 volume control.
70	Nr42 = 0xFF21,
71	/// CH4 LFSR control.
72	Nr43 = 0xFF22,
73	/// CH4 control.
74	Nr44 = 0xFF23,
75	/// Master volume & VIN panning.
76	Nr50 = 0xFF24,
77	/// Sound panning.
78	Nr51 = 0xFF25,
79	/// Audio control.
80	Nr52 = 0xFF26,
81
82	Wave0 = 0xFF30,
83	Wave1 = 0xFF31,
84	Wave2 = 0xFF32,
85	Wave3 = 0xFF33,
86	Wave4 = 0xFF34,
87	Wave5 = 0xFF35,
88	Wave6 = 0xFF36,
89	Wave7 = 0xFF37,
90	Wave8 = 0xFF38,
91	Wave9 = 0xFF39,
92	WaveA = 0xFF3A,
93	WaveB = 0xFF3B,
94	WaveC = 0xFF3C,
95	WaveD = 0xFF3D,
96	WaveE = 0xFF3E,
97	WaveF = 0xFF3F,
98
99	/// LCD control.
100	Lcdc = 0xFF40,
101	/// LCD status.
102	Stat = 0xFF41,
103	/// Viewport vertical offset.
104	Scy = 0xFF42,
105	/// Viewport horizontal offset.
106	Scx = 0xFF43,
107	/// Current scanline.
108	Ly = 0xFF44,
109	/// LY comparison.
110	Lyc = 0xFF45,
111	/// OAM DMA source & start.
112	Dma = 0xFF46,
113	/// DMG background palette.
114	Bgp = 0xFF47,
115	/// DMG OBJ palette 0.
116	Obp0 = 0xFF48,
117	/// DMG OBJ palette 1.
118	Obp1 = 0xFF49,
119	/// Window Y coordinate.
120	Wy = 0xFF4A,
121	/// Window X coordinate.
122	Wx = 0xFF4B,
123
124	/// CGB speed switch.
125	Key1 = 0xFF4D,
126
127	/// CGB VRAM bank switch.
128	Vbk = 0xFF4F,
129
130	/// CGB DMA source, upper 8 bits.
131	Hdma1 = 0xFF51,
132	/// CGB DMA source, lower 8 bits.
133	Hdma2 = 0xFF52,
134	/// CGB DMA destination, upper 8 bits.
135	Hdma3 = 0xFF53,
136	/// CGB DMA destination, lower 8 bits.
137	Hdma4 = 0xFF54,
138	/// CGB DMA length & mode & start.
139	Hdma5 = 0xFF55,
140
141	/// CGB IR.
142	Rp = 0xFF56,
143
144	/// CGB BG palette address.
145	Bcps = 0xFF68,
146	/// CGB BG palette data.
147	Bcpd = 0xFF69,
148	/// CGB OBJ palette address.
149	Ocps = 0xFF6A,
150	/// CGB OBJ palette data.
151	Ocpd = 0xFF6B,
152
153	/// CGB WRAM bank switch.
154	Svbk = 0xFF70,
155
156	/// CH1 & CH2 digital output.
157	Pcm12 = 0xFF76,
158	/// CH3 & CH4 digital output.
159	Pcm34 = 0xFF77,
160
161	/// Enabled interrupts.
162	Ie = 0xFFFF,
163}
164
165impl From<HwReg> for u16 {
166	fn from(reg: HwReg) -> Self {
167		reg as u16
168	}
169}
170
171#[derive(Default)]
172pub struct Mmio {
173	ramg: u8,
174	romb0: u8,
175	romb1: u8,
176	ramb: u8,
177	rtclatch: u8,
178	p1: u8,
179	sb: u8,
180	sc: u8,
181	div: u8,
182	tima: u8,
183	tma: u8,
184	tac: u8,
185	_if: u8,
186	// Sound registers
187	nr10: u8,
188	nr11: u8,
189	nr12: u8,
190	nr13: u8,
191	nr14: u8,
192	nr21: u8,
193	nr22: u8,
194	nr23: u8,
195	nr24: u8,
196	nr30: u8,
197	nr31: u8,
198	nr32: u8,
199	nr33: u8,
200	nr34: u8,
201	nr41: u8,
202	nr42: u8,
203	nr43: u8,
204	nr44: u8,
205	nr50: u8,
206	nr51: u8,
207	nr52: u8,
208	wave_0: u8,
209	wave_1: u8,
210	wave_2: u8,
211	wave_3: u8,
212	wave_4: u8,
213	wave_5: u8,
214	wave_6: u8,
215	wave_7: u8,
216	wave_8: u8,
217	wave_9: u8,
218	wave_a: u8,
219	wave_b: u8,
220	wave_c: u8,
221	wave_d: u8,
222	wave_e: u8,
223	wave_f: u8,
224	lcdc: u8,
225	stat: u8,
226	scy: u8,
227	scx: u8,
228	ly: u8,
229	lyc: u8,
230	dma: u8,
231	bgp: u8,
232	obp0: u8,
233	obp1: u8,
234	wy: u8,
235	wx: u8,
236	key1: u8,
237	vbk: u8,
238	hdma1: u8,
239	hdma2: u8,
240	hdma3: u8,
241	hdma4: u8,
242	hdma5: u8,
243	rp: u8,
244	bcps: u8,
245	bcpd: u8,
246	ocps: u8,
247	ocpd: u8,
248	svbk: u8,
249	pcm12: u8,
250	pcm34: u8,
251	ie: u8,
252}
253
254impl Mmio {
255	pub fn read(&self, register: HwReg) -> u8 {
256		match register {
257			HwReg::Ramg => self.ramg,
258			HwReg::Romb0 => self.romb0,
259			HwReg::Romb1 => self.romb1,
260			HwReg::Ramb => self.ramb,
261			HwReg::Rtclatch => self.rtclatch,
262			HwReg::P1 => {
263				// TODO: Allow the user to define a set of pressed buttons to loosely implement rP1.
264				eprintln!("Unit test has no joypad input");
265				self.p1
266			}
267			HwReg::Sb => {
268				// TODO: Allow the user to define a stream of bytes to read through rSB.
269				eprintln!("Unit test has no serial input");
270				self.sb
271			}
272			HwReg::Sc => self.sc,
273			HwReg::Div => self.div,
274			HwReg::Tima => self.tima,
275			HwReg::Tma => self.tma,
276			HwReg::Tac => self.tac,
277			HwReg::If => self._if,
278			HwReg::Nr10 => self.nr10,
279			HwReg::Nr11 => self.nr11,
280			HwReg::Nr12 => self.nr12,
281			HwReg::Nr13 => self.nr13,
282			HwReg::Nr14 => self.nr14,
283			HwReg::Nr21 => self.nr21,
284			HwReg::Nr22 => self.nr22,
285			HwReg::Nr23 => self.nr23,
286			HwReg::Nr24 => self.nr24,
287			HwReg::Nr30 => self.nr30,
288			HwReg::Nr31 => self.nr31,
289			HwReg::Nr32 => self.nr32,
290			HwReg::Nr33 => self.nr33,
291			HwReg::Nr34 => self.nr34,
292			HwReg::Nr41 => self.nr41,
293			HwReg::Nr42 => self.nr42,
294			HwReg::Nr43 => self.nr43,
295			HwReg::Nr44 => self.nr44,
296			HwReg::Nr50 => self.nr50,
297			HwReg::Nr51 => self.nr51,
298			HwReg::Nr52 => self.nr52,
299			HwReg::Wave0 => self.wave_0,
300			HwReg::Wave1 => self.wave_1,
301			HwReg::Wave2 => self.wave_2,
302			HwReg::Wave3 => self.wave_3,
303			HwReg::Wave4 => self.wave_4,
304			HwReg::Wave5 => self.wave_5,
305			HwReg::Wave6 => self.wave_6,
306			HwReg::Wave7 => self.wave_7,
307			HwReg::Wave8 => self.wave_8,
308			HwReg::Wave9 => self.wave_9,
309			HwReg::WaveA => self.wave_a,
310			HwReg::WaveB => self.wave_b,
311			HwReg::WaveC => self.wave_c,
312			HwReg::WaveD => self.wave_d,
313			HwReg::WaveE => self.wave_e,
314			HwReg::WaveF => self.wave_f,
315			HwReg::Lcdc => self.lcdc,
316			HwReg::Stat => self.stat,
317			HwReg::Scy => self.scy,
318			HwReg::Scx => self.scx,
319			HwReg::Ly => self.ly,
320			HwReg::Lyc => self.lyc,
321			HwReg::Dma => self.dma,
322			HwReg::Bgp => self.bgp,
323			HwReg::Obp0 => self.obp0,
324			HwReg::Obp1 => self.obp1,
325			HwReg::Wy => self.wy,
326			HwReg::Wx => self.wx,
327			HwReg::Key1 => self.key1,
328			HwReg::Vbk => self.vbk,
329			HwReg::Hdma1 => self.hdma1,
330			HwReg::Hdma2 => self.hdma2,
331			HwReg::Hdma3 => self.hdma3,
332			HwReg::Hdma4 => self.hdma4,
333			HwReg::Hdma5 => self.hdma5,
334			HwReg::Rp => self.rp,
335			HwReg::Bcps => self.bcps,
336			HwReg::Bcpd => self.bcpd,
337			HwReg::Ocps => self.ocps,
338			HwReg::Ocpd => self.ocpd,
339			HwReg::Svbk => self.svbk,
340			HwReg::Pcm12 => self.pcm12,
341			HwReg::Pcm34 => self.pcm34,
342			HwReg::Ie => self.ie,
343		}
344	}
345
346	pub fn write(&mut self, register: HwReg, value: u8) {
347		match register {
348			HwReg::Ramg => self.ramg = value,
349			HwReg::Romb0 => self.romb0 = value,
350			HwReg::Romb1 => self.romb1 = value,
351			HwReg::Ramb => self.ramb = value,
352			HwReg::Rtclatch => self.rtclatch = value,
353			HwReg::P1 => self.p1 = value,
354			HwReg::Sb => self.sb = value,
355			HwReg::Sc => self.sc = value,
356			HwReg::Div => self.div = value,
357			HwReg::Tima => self.tima = value,
358			HwReg::Tma => self.tma = value,
359			HwReg::Tac => self.tac = value,
360			HwReg::If => self._if = value,
361			HwReg::Nr10 => self.nr10 = value,
362			HwReg::Nr11 => self.nr11 = value,
363			HwReg::Nr12 => self.nr12 = value,
364			HwReg::Nr13 => self.nr13 = value,
365			HwReg::Nr14 => self.nr14 = value,
366			HwReg::Nr21 => self.nr21 = value,
367			HwReg::Nr22 => self.nr22 = value,
368			HwReg::Nr23 => self.nr23 = value,
369			HwReg::Nr24 => self.nr24 = value,
370			HwReg::Nr30 => self.nr30 = value,
371			HwReg::Nr31 => self.nr31 = value,
372			HwReg::Nr32 => self.nr32 = value,
373			HwReg::Nr33 => self.nr33 = value,
374			HwReg::Nr34 => self.nr34 = value,
375			HwReg::Nr41 => self.nr41 = value,
376			HwReg::Nr42 => self.nr42 = value,
377			HwReg::Nr43 => self.nr43 = value,
378			HwReg::Nr44 => self.nr44 = value,
379			HwReg::Nr50 => self.nr50 = value,
380			HwReg::Nr51 => self.nr51 = value,
381			HwReg::Nr52 => self.nr52 = value,
382			HwReg::Wave0 => self.wave_0 = value,
383			HwReg::Wave1 => self.wave_1 = value,
384			HwReg::Wave2 => self.wave_2 = value,
385			HwReg::Wave3 => self.wave_3 = value,
386			HwReg::Wave4 => self.wave_4 = value,
387			HwReg::Wave5 => self.wave_5 = value,
388			HwReg::Wave6 => self.wave_6 = value,
389			HwReg::Wave7 => self.wave_7 = value,
390			HwReg::Wave8 => self.wave_8 = value,
391			HwReg::Wave9 => self.wave_9 = value,
392			HwReg::WaveA => self.wave_a = value,
393			HwReg::WaveB => self.wave_b = value,
394			HwReg::WaveC => self.wave_c = value,
395			HwReg::WaveD => self.wave_d = value,
396			HwReg::WaveE => self.wave_e = value,
397			HwReg::WaveF => self.wave_f = value,
398			HwReg::Lcdc => self.lcdc = value,
399			HwReg::Stat => self.stat = value,
400			HwReg::Scy => self.scy = value,
401			HwReg::Scx => self.scx = value,
402			HwReg::Ly => self.ly = value,
403			HwReg::Lyc => self.lyc = value,
404			HwReg::Dma => self.dma = value,
405			HwReg::Bgp => self.bgp = value,
406			HwReg::Obp0 => self.obp0 = value,
407			HwReg::Obp1 => self.obp1 = value,
408			HwReg::Wy => self.wy = value,
409			HwReg::Wx => self.wx = value,
410			HwReg::Key1 => self.key1 = value,
411			HwReg::Vbk => self.vbk = value,
412			HwReg::Hdma1 => self.hdma1 = value,
413			HwReg::Hdma2 => self.hdma2 = value,
414			HwReg::Hdma3 => self.hdma3 = value,
415			HwReg::Hdma4 => self.hdma4 = value,
416			HwReg::Hdma5 => self.hdma5 = value,
417			HwReg::Rp => self.rp = value,
418			HwReg::Bcps => self.bcps = value,
419			HwReg::Bcpd => self.bcpd = value,
420			HwReg::Ocps => self.ocps = value,
421			HwReg::Ocpd => self.ocpd = value,
422			HwReg::Svbk => self.svbk = value,
423			HwReg::Pcm12 => self.pcm12 = value,
424			HwReg::Pcm34 => self.pcm34 = value,
425			HwReg::Ie => self.ie = value,
426		}
427	}
428
429	pub fn new() -> Mmio {
430		Default::default()
431	}
432}