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
143
//!
//! `rgy` is no-std cross-platform Rust GameBoy emulator library.
//!
//! The users of this library only needs to implement [`Hardware`][] trait, which abstracts OS-specific function.
//! Once it's implemented, the emulator works.
//!
//! The following code is the example which just implements `Hardware`. The implementation does nothing.
//! You can replace the body of each function with the actual meaningful logic.
//!
//! ```rust,no_run
//! use rgy::{Config, Key, Stream, VRAM_HEIGHT, VRAM_WIDTH};
//!
//! struct Hardware {
//! dummy_display: Vec<Vec<u32>>,
//! }
//!
//! impl Hardware {
//! fn new() -> Self {
//! // Create a frame buffer with the size VRAM_WIDTH * VRAM_HEIGHT.
//! let dummy_display = vec![vec![0u32; VRAM_HEIGHT]; VRAM_WIDTH];
//!
//! Self { dummy_display }
//! }
//! }
//!
//! impl rgy::Hardware for Hardware {
//! // Called when a horizontal line in the display is updated by the emulator.
//! fn vram_update(&mut self, line: usize, buffer: &[u32]) {
//! // `line` corresponds to the y coordinate.
//! let y = line;
//!
//! for (x, col) in buffer.iter().enumerate() {
//! // TODO: Update the pixels in the actual display here.
//! self.dummy_display[x][y] = *col;
//! }
//! }
//!
//! // Called when the emulator checks if a key is pressed or not.
//! fn joypad_pressed(&mut self, key: Key) -> bool {
//! println!("Is {:?} pressed?", key);
//!
//! // TODO: Read a keyboard device and check if the `key` is pressed or not.
//!
//! false
//! }
//!
//! // Called when the emulator plays a sound.
//! fn sound_play(&mut self, _stream: Box<dyn Stream>) {
//! // TODO: Play the wave pattern provided `Stream`.
//! }
//!
//! // Provides clock for the emulator.
//! fn clock(&mut self) -> u64 {
//! // TODO: Return the epoch in microseconds.
//! let epoch = std::time::SystemTime::now()
//! .duration_since(std::time::UNIX_EPOCH)
//! .expect("Couldn't get epoch");
//! epoch.as_micros() as u64
//! }
//!
//! // Called when the emulator sends a byte to the serial port.
//! fn send_byte(&mut self, _b: u8) {
//! // TODO: Send a byte to a serial port.
//! }
//!
//! // Called when the emulator peeks a byte from the serial port.
//! fn recv_byte(&mut self) -> Option<u8> {
//! // TODO: Check the status of the serial port and read a byte if any.
//! None
//! }
//!
//! // Called every time the emulator executes an instruction.
//! fn sched(&mut self) -> bool {
//! // TODO: Do some periodic jobs if any. Return `true` to continue, `false` to stop the emulator.
//! println!("It's running!");
//! true
//! }
//!
//! // Called when the emulator stores the save data to the battery-backed RAM.
//! fn load_ram(&mut self, size: usize) -> Vec<u8> {
//! // TODO: Return save data.
//! vec![0; size]
//! }
//!
//! // Called when the emulator loads the save data from the battery-backed RAM.
//! fn save_ram(&mut self, _ram: &[u8]) {
//! // TODO: Store save data.
//! }
//! }
//!
//! fn main() {
//! // Create the default config.
//! let cfg = Config::new();
//!
//! // Create the hardware instance.
//! let hw = Hardware::new();
//!
//! // TODO: The content of a ROM file, which can be downloaded from the Internet.
//! let rom = vec![0u8; 1024];
//!
//! // Run the emulator.
//! rgy::run(cfg, &rom, hw);
//! }
//! ```
extern crate alloc;
/// CPU state.
/// Debugger interface.
/// Adaptor to register devices to MMU.
/// Decoder which evaluates each CPU instructions.
/// Handles memory and I/O port access from the CPU.
/// Hardware interface, which abstracts OS-specific functions.
pub use crate;
pub use crate;