pyboy 2.5.3__tar.gz → 2.6.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (120) hide show
  1. pyboy-2.6.0/PKG-INFO +228 -0
  2. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy/core/lcd.py +21 -19
  3. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy/core/mb.pxd +3 -1
  4. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy/core/mb.py +31 -9
  5. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy/core/ram.pxd +2 -1
  6. pyboy-2.6.0/pyboy/core/serial.pxd +29 -0
  7. pyboy-2.6.0/pyboy/core/serial.py +78 -0
  8. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy/core/sound.pxd +2 -2
  9. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy/core/sound.py +24 -16
  10. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy/core/timer.pxd +1 -0
  11. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy/core/timer.py +3 -1
  12. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy/plugins/rewind.pxd +2 -2
  13. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy/plugins/rewind.py +14 -6
  14. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy/plugins/window_sdl2.py +1 -1
  15. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy/utils.pxd +7 -0
  16. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy/utils.py +17 -1
  17. pyboy-2.6.0/pyboy.egg-info/PKG-INFO +228 -0
  18. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy.egg-info/SOURCES.txt +2 -0
  19. {pyboy-2.5.3 → pyboy-2.6.0}/pyproject.toml +3 -4
  20. {pyboy-2.5.3 → pyboy-2.6.0}/setup.py +7 -2
  21. pyboy-2.5.3/PKG-INFO +0 -392
  22. pyboy-2.5.3/pyboy.egg-info/PKG-INFO +0 -392
  23. {pyboy-2.5.3 → pyboy-2.6.0}/LICENSE.md +0 -0
  24. {pyboy-2.5.3 → pyboy-2.6.0}/MANIFEST.in +0 -0
  25. {pyboy-2.5.3 → pyboy-2.6.0}/README.md +0 -0
  26. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy/__init__.py +0 -0
  27. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy/__main__.py +0 -0
  28. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy/api/__init__.py +0 -0
  29. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy/api/constants.py +0 -0
  30. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy/api/gameshark.pxd +0 -0
  31. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy/api/gameshark.py +0 -0
  32. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy/api/memory_scanner.pxd +0 -0
  33. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy/api/memory_scanner.py +0 -0
  34. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy/api/screen.pxd +0 -0
  35. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy/api/screen.py +0 -0
  36. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy/api/sound.pxd +0 -0
  37. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy/api/sound.py +0 -0
  38. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy/api/sprite.pxd +0 -0
  39. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy/api/sprite.py +0 -0
  40. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy/api/tile.pxd +0 -0
  41. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy/api/tile.py +0 -0
  42. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy/api/tilemap.pxd +0 -0
  43. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy/api/tilemap.py +0 -0
  44. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy/conftest.py +0 -0
  45. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy/core/__init__.py +0 -0
  46. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy/core/bootrom.pxd +0 -0
  47. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy/core/bootrom.py +0 -0
  48. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy/core/bootrom_cgb.bin +0 -0
  49. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy/core/bootrom_dmg.bin +0 -0
  50. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy/core/cartridge/__init__.py +0 -0
  51. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy/core/cartridge/base_mbc.pxd +0 -0
  52. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy/core/cartridge/base_mbc.py +0 -0
  53. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy/core/cartridge/cartridge.pxd +0 -0
  54. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy/core/cartridge/cartridge.py +0 -0
  55. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy/core/cartridge/mbc1.pxd +0 -0
  56. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy/core/cartridge/mbc1.py +0 -0
  57. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy/core/cartridge/mbc2.pxd +0 -0
  58. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy/core/cartridge/mbc2.py +0 -0
  59. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy/core/cartridge/mbc3.pxd +0 -0
  60. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy/core/cartridge/mbc3.py +0 -0
  61. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy/core/cartridge/mbc5.pxd +0 -0
  62. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy/core/cartridge/mbc5.py +0 -0
  63. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy/core/cartridge/rtc.pxd +0 -0
  64. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy/core/cartridge/rtc.py +0 -0
  65. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy/core/cpu.pxd +0 -0
  66. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy/core/cpu.py +0 -0
  67. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy/core/interaction.pxd +0 -0
  68. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy/core/interaction.py +0 -0
  69. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy/core/lcd.pxd +0 -0
  70. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy/core/opcodes.pxd +0 -0
  71. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy/core/opcodes.py +0 -0
  72. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy/core/opcodes_gen.py +0 -0
  73. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy/core/ram.py +0 -0
  74. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy/default_rom.gb +0 -0
  75. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy/logging/__init__.py +0 -0
  76. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy/logging/_logging.py +0 -0
  77. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy/logging/logging.pxd +0 -0
  78. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy/logging/logging.pyx +0 -0
  79. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy/plugins/__init__.py +0 -0
  80. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy/plugins/auto_pause.pxd +0 -0
  81. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy/plugins/auto_pause.py +0 -0
  82. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy/plugins/base_plugin.pxd +0 -0
  83. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy/plugins/base_plugin.py +0 -0
  84. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy/plugins/debug.pxd +0 -0
  85. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy/plugins/debug.py +0 -0
  86. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy/plugins/debug_prompt.pxd +0 -0
  87. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy/plugins/debug_prompt.py +0 -0
  88. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy/plugins/font.txt +0 -0
  89. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy/plugins/game_wrapper_kirby_dream_land.pxd +0 -0
  90. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy/plugins/game_wrapper_kirby_dream_land.py +0 -0
  91. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy/plugins/game_wrapper_pokemon_gen1.pxd +0 -0
  92. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy/plugins/game_wrapper_pokemon_gen1.py +0 -0
  93. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy/plugins/game_wrapper_pokemon_pinball.pxd +0 -0
  94. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy/plugins/game_wrapper_pokemon_pinball.py +0 -0
  95. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy/plugins/game_wrapper_super_mario_land.pxd +0 -0
  96. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy/plugins/game_wrapper_super_mario_land.py +0 -0
  97. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy/plugins/game_wrapper_tetris.pxd +0 -0
  98. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy/plugins/game_wrapper_tetris.py +0 -0
  99. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy/plugins/manager.pxd +0 -0
  100. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy/plugins/manager.py +0 -0
  101. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy/plugins/manager_gen.py +0 -0
  102. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy/plugins/record_replay.pxd +0 -0
  103. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy/plugins/record_replay.py +0 -0
  104. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy/plugins/screen_recorder.pxd +0 -0
  105. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy/plugins/screen_recorder.py +0 -0
  106. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy/plugins/screenshot_recorder.pxd +0 -0
  107. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy/plugins/screenshot_recorder.py +0 -0
  108. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy/plugins/window_null.pxd +0 -0
  109. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy/plugins/window_null.py +0 -0
  110. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy/plugins/window_open_gl.pxd +0 -0
  111. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy/plugins/window_open_gl.py +0 -0
  112. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy/plugins/window_sdl2.pxd +0 -0
  113. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy/pyboy.pxd +0 -0
  114. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy/pyboy.py +0 -0
  115. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy.egg-info/dependency_links.txt +0 -0
  116. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy.egg-info/entry_points.txt +0 -0
  117. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy.egg-info/not-zip-safe +0 -0
  118. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy.egg-info/requires.txt +0 -0
  119. {pyboy-2.5.3 → pyboy-2.6.0}/pyboy.egg-info/top_level.txt +0 -0
  120. {pyboy-2.5.3 → pyboy-2.6.0}/setup.cfg +0 -0
pyboy-2.6.0/PKG-INFO ADDED
@@ -0,0 +1,228 @@
1
+ Metadata-Version: 2.4
2
+ Name: pyboy
3
+ Version: 2.6.0
4
+ Summary: Game Boy emulator written in Python
5
+ Author-email: Mads Ynddal <mads@ynddal.dk>
6
+ License-Expression: LGPL-3.0-only
7
+ Project-URL: Homepage, https://github.com/Baekalfen/PyBoy
8
+ Project-URL: Documentation, https://docs.pyboy.dk/index.html
9
+ Project-URL: Repository, https://github.com/Baekalfen/PyBoy.git
10
+ Keywords: gameboy,game boy,emulator,cython,pypy
11
+ Classifier: Operating System :: OS Independent
12
+ Classifier: Programming Language :: Cython
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: Implementation :: PyPy
15
+ Classifier: Topic :: System :: Emulators
16
+ Requires-Python: >=3.9
17
+ Description-Content-Type: text/markdown
18
+ License-File: LICENSE.md
19
+ Requires-Dist: numpy
20
+ Requires-Dist: pysdl2
21
+ Requires-Dist: pysdl2-dll
22
+ Provides-Extra: all
23
+ Requires-Dist: pyopengl; extra == "all"
24
+ Requires-Dist: markdown; extra == "all"
25
+ Requires-Dist: pdoc3; extra == "all"
26
+ Requires-Dist: gym; extra == "all"
27
+ Dynamic: license-file
28
+
29
+ <p align="center">
30
+ <img src="extras/README/pyboy.svg" width="480">
31
+ </p>
32
+
33
+ __If you have any questions, or just want to chat, [join us on Discord](https://discord.gg/wUbag3KNqQ).__
34
+
35
+ [![Discord](https://img.shields.io/discord/584149554132418570?style=for-the-badge&logo=Discord&label=PyBoy)](https://discord.gg/wUbag3KNqQ)
36
+
37
+ <!---
38
+ Generate GIF with the layout and captions
39
+ -->
40
+ <table>
41
+ <tbody>
42
+ <tr>
43
+ <td colspan=2 align="center"><a href=https://github.com/PWhiddy/PokemonRedExperiments>Train RL agents to play Pokemon Red</a>
44
+ </td>
45
+ <td align="center"><a href=https://github.com/Baekalfen/PyBoy/wiki/Experimental-and-optional-features#rewind-time>Rewind any game</a><br>
46
+ </td>
47
+ </tr>
48
+ <tr>
49
+ <td colspan=2 align="center">
50
+ <div align="center">
51
+ <a href="http://www.youtube.com/watch?feature=player_embedded&v=DcYLT37ImBY" target="_blank">
52
+ <img src="http://img.youtube.com/vi/DcYLT37ImBY/maxresdefault.jpg" alt="Watch the video" width="500" border="10" />
53
+ <!-- <img src="http://img.youtube.com/vi/DcYLT37ImBY/hqdefault.jpg" alt="Watch the video" width="500" border="10" /> -->
54
+ </a>
55
+ <!-- https://www.youtube.com/watch?v=DcYLT37ImBY -->
56
+ <!-- <img src="extras/README/8.gif" width="400"><br> -->
57
+ </div>
58
+ </td>
59
+ <td align="center">
60
+ <img src="extras/README/5.gif" width="250">
61
+ </td>
62
+ </tr>
63
+ <tr>
64
+ <td align="center">Play the classics<br>
65
+ </td>
66
+ <td align="center"><a href=https://github.com/lixado/PyBoy-RL>Create your own AI</a><br>
67
+ </td>
68
+ <td align="center"><a href=https://github.com/uiucanh/tetris>Beat world records with AI</a><br>
69
+ </td>
70
+ </tr>
71
+ <tr>
72
+ <td align="center">
73
+ <img src="extras/README/1.gif" width="250">
74
+ </td>
75
+ <td align="center">
76
+ <img src="extras/README/6.gif" width="250">
77
+ </td>
78
+ <td align="center">
79
+ <img src="extras/README/7.gif" width="250">
80
+ </td>
81
+ </tr>
82
+ </tbody>
83
+ </table>
84
+
85
+ Getting Started
86
+ ===============
87
+ The instructions are simple:
88
+
89
+ ```sh
90
+ $ pip install pyboy
91
+ ```
92
+
93
+ For details, see [installation instructions](https://github.com/Baekalfen/PyBoy/wiki/Installation).
94
+
95
+ Now you're ready! Either use PyBoy directly from the terminal
96
+ ```sh
97
+ $ pyboy game_rom.gb
98
+ ```
99
+
100
+ Or use it in your Python scripts:
101
+ ```python
102
+ from pyboy import PyBoy
103
+ pyboy = PyBoy('game_rom.gb')
104
+ while pyboy.tick():
105
+ pass
106
+ pyboy.stop()
107
+ ```
108
+
109
+ <!-- Or using the context manager:
110
+ ```python
111
+ from pyboy import PyBoy
112
+ with PyBoy('game_rom.gb') as pyboy:
113
+ while pyboy.tick():
114
+ pass
115
+ ``` -->
116
+
117
+
118
+ The API
119
+ =======
120
+
121
+ If you are looking to make a bot or AI, then these resources are a good place to start:
122
+ * [PyBoy API Documentation](https://baekalfen.github.io/PyBoy/index.html)
123
+ * [Wiki Pages](https://github.com/Baekalfen/PyBoy/wiki/)
124
+ * [Using PyBoy with Gym](https://github.com/Baekalfen/PyBoy/wiki/Using-PyBoy-with-Gym)
125
+ * [Example: Kirby](https://github.com/Baekalfen/PyBoy/wiki/Example-Kirby)
126
+ * [Example: Tetris](https://github.com/Baekalfen/PyBoy/wiki/Example-Tetris)
127
+ * [Example: Super Mario Land](https://github.com/Baekalfen/PyBoy/wiki/Example-Super-Mario-Land)
128
+ * [Code Examples](https://github.com/Baekalfen/PyBoy/tree/master/extras/examples)
129
+ * [Discord](https://discord.gg/wUbag3KNqQ)
130
+
131
+
132
+ When the emulator is running, you can easily access [PyBoy's API](https://baekalfen.github.io/PyBoy/index.html):
133
+ ```python
134
+ pyboy.set_emulation_speed(0) # No speed limit
135
+ pyboy.button('down')
136
+ pyboy.button('a')
137
+ pyboy.tick() # Process at least one frame to let the game register the input
138
+ value_of_interest = pyboy.memory[0xC345]
139
+
140
+ pil_image = pyboy.screen.image
141
+ pil_image.save('screenshot.png')
142
+ ```
143
+
144
+ The [Wiki](https://github.com/Baekalfen/PyBoy/wiki) shows how to interface with PyBoy from your own project.
145
+
146
+ Performance
147
+ ===========
148
+
149
+ Performance is a priority for PyBoy, to make your AI training and scripts as fast as possible.
150
+
151
+ The easiest way to improve your performance, is to skip rendering of unnecessary frames. If you know your
152
+ character takes X frames to move, or the game doesn't take input every frame, you can skip those to potentially triple
153
+ your performance. All game logic etc. will still process.
154
+
155
+ Here is a simple comparison of rendering every frame, rendering every 15th frame, and not rendering any frames (higher is better). See [`pyboy.tick`](https://docs.pyboy.dk/#pyboy.PyBoy.tick) for how it works. Your performance will depend on the game.
156
+
157
+ <table>
158
+ <tbody>
159
+ <tr>
160
+ <td align="center">
161
+ Full rendering
162
+ </td>
163
+ <td align="center">
164
+ Frame-skip 15
165
+ </td>
166
+ <td align="center">
167
+ No rendering
168
+ </td>
169
+ </tr>
170
+ <tr>
171
+ <td>
172
+ x124 realtime
173
+ </td>
174
+ <td>
175
+ x344 realtime
176
+ </td>
177
+ <td>
178
+ x395 realtime
179
+ </td>
180
+ </tr>
181
+ <tr> <!-- Markdown/HTML broken after this -->
182
+ <td>
183
+
184
+ ```python
185
+ for _ in range(target):
186
+ pyboy.tick()
187
+
188
+ ```
189
+ </td>
190
+ <td >
191
+
192
+ ```python
193
+ for _ in range(target//15):
194
+ pyboy.tick(15)
195
+
196
+ ```
197
+ </td>
198
+ <td >
199
+
200
+ ```python
201
+ pyboy.tick(target, False)
202
+
203
+ ```
204
+ </td>
205
+ </tr>
206
+ </tbody>
207
+ </table>
208
+
209
+ The Game Boy was originally running at 60 frames per second, so a speed-up of 100x realtime is 6,000 frames per
210
+ second. And trivially from the table above, simulating 395 hours of gameplay can be done in 1 hour with no rendering.
211
+
212
+ It's also recommended to be running multiple instances of PyBoy in parallel. On an 8-core machine, you could potentially
213
+ do 3160 hours of gameplay in 1 hour.
214
+
215
+ Contributing
216
+ ============
217
+ Any contribution is appreciated. The currently known problems are tracked in [the Issues tab](https://github.com/Baekalfen/PyBoy/issues). Feel free to take a swing at any one of them. If you have something original in mind, come and [discuss it on on Discord](https://discord.gg/wUbag3KNqQ).
218
+
219
+ [![Discord](https://img.shields.io/discord/584149554132418570?style=for-the-badge&logo=Discord&label=PyBoy)](https://discord.gg/wUbag3KNqQ)
220
+
221
+ For the more major features, there are the following that you can give a try. They are also described in more detail in the [project list in the Wiki](https://github.com/Baekalfen/PyBoy/wiki/Student-Projects):
222
+ * Hacking games
223
+ * Link Cable
224
+ * Debugger (VSCode, GDB, terminal or otherwise)
225
+ * AI - [use the `api`](https://baekalfen.github.io/PyBoy/index.html) or game wrappers to train a neural network
226
+ * Game Wrappers - make wrappers for popular games
227
+
228
+ If you want to implement something which is not on the list, feel free to do so anyway. If you want to merge it into our repo, then just send a pull request and we will have a look at it.
@@ -42,12 +42,12 @@ class LCD:
42
42
 
43
43
  self.speed_shift = 0
44
44
  self.clock = 0
45
- self.clock_target = FRAME_CYCLES << self.speed_shift
45
+ self.clock_target = FRAME_CYCLES
46
46
  self.frame_done = False
47
47
  self.first_frame = False
48
48
  self.reset = False
49
49
  self._cycles_to_interrupt = 0
50
- self._cycles_to_frame = (FRAME_CYCLES << self.speed_shift) - self.clock
50
+ self._cycles_to_frame = (FRAME_CYCLES - self.clock) << self.speed_shift
51
51
  self.next_stat_mode = 2
52
52
  self.LY = 0x00
53
53
  self._STAT.set_mode(0)
@@ -63,7 +63,7 @@ class LCD:
63
63
  self._scanlineparameters = [[0, 0, 0, 0, 0] for _ in range(ROWS)]
64
64
  self.last_cycles = 0
65
65
  self._cycles_to_interrupt = 0
66
- self._cycles_to_frame = (FRAME_CYCLES << self.speed_shift) - self.clock
66
+ self._cycles_to_frame = (FRAME_CYCLES - self.clock) << self.speed_shift
67
67
 
68
68
  if self.cgb:
69
69
  # Setting for both modes, even though CGB is ignoring them. BGP[0] used in scanline_blank.
@@ -115,9 +115,9 @@ class LCD:
115
115
  self.reset = True
116
116
 
117
117
  def cycles_to_mode0(self):
118
- mode2 = 80 << self.speed_shift
119
- mode3 = 170 << self.speed_shift
120
- mode1 = 456 << self.speed_shift
118
+ mode2 = 80
119
+ mode3 = 170
120
+ mode1 = 456
121
121
 
122
122
  mode = self._STAT._mode
123
123
  # Remaining cycles for this already active mode
@@ -144,7 +144,7 @@ class LCD:
144
144
  self.last_cycles = _cycles
145
145
 
146
146
  interrupt_flag = 0
147
- self.clock += cycles
147
+ self.clock += cycles >> self.speed_shift
148
148
 
149
149
  if self.clock >= self.clock_target:
150
150
  if self._LCDC.lcd_enable and (self.LY == 153 or self.reset):
@@ -159,7 +159,7 @@ class LCD:
159
159
 
160
160
  # Reset to new frame and start from mode 2
161
161
  self.LY = 0
162
- self.clock %= FRAME_CYCLES << self.speed_shift
162
+ self.clock %= FRAME_CYCLES
163
163
  self.clock_target = 0
164
164
  self.next_stat_mode = 2
165
165
 
@@ -167,7 +167,7 @@ class LCD:
167
167
  interrupt_flag |= self._STAT.set_mode(self.next_stat_mode)
168
168
 
169
169
  # self._STAT._mode == 2: # Searching OAM
170
- self.clock_target += 80 << self.speed_shift
170
+ self.clock_target += 80
171
171
  self.next_stat_mode = 3
172
172
  interrupt_flag |= self._STAT.update_LYC(self.LYC, self.LY)
173
173
 
@@ -185,14 +185,14 @@ class LCD:
185
185
  # LCD state machine
186
186
  if self._STAT._mode == 2: # Searching OAM
187
187
  self.LY += 1
188
- self.clock_target += 80 << self.speed_shift
188
+ self.clock_target += 80
189
189
  self.next_stat_mode = 3
190
190
  interrupt_flag |= self._STAT.update_LYC(self.LYC, self.LY)
191
191
  elif self._STAT._mode == 3:
192
- self.clock_target += 170 << self.speed_shift
192
+ self.clock_target += 170
193
193
  self.next_stat_mode = 0
194
194
  elif self._STAT._mode == 0: # HBLANK
195
- self.clock_target += 206 << self.speed_shift
195
+ self.clock_target += 206
196
196
 
197
197
  # Recorded for API
198
198
  bx, by = self.getviewport()
@@ -212,7 +212,7 @@ class LCD:
212
212
  else:
213
213
  self.next_stat_mode = 1
214
214
  elif self._STAT._mode == 1: # VBLANK
215
- self.clock_target += 456 << self.speed_shift
215
+ self.clock_target += 456
216
216
  self.next_stat_mode = 1
217
217
 
218
218
  self.LY += 1
@@ -229,15 +229,16 @@ class LCD:
229
229
  else:
230
230
  # See also `self.set_lcdc`
231
231
  self.frame_done = True
232
- self.clock %= FRAME_CYCLES << self.speed_shift
233
- self.clock_target = FRAME_CYCLES << self.speed_shift
232
+ self.clock %= FRAME_CYCLES
233
+ self.clock_target = FRAME_CYCLES
234
234
 
235
235
  # Renderer
236
236
  self.renderer.blank_screen(self)
237
237
 
238
- self._cycles_to_interrupt = self.clock_target - self.clock
238
+ # NOTE: speed_shift because they are using in externally in mb
239
+ self._cycles_to_interrupt = (self.clock_target - self.clock) << self.speed_shift
239
240
  # TODO: STAT Cycles to interrupts
240
- self._cycles_to_frame = (FRAME_CYCLES << self.speed_shift) - self.clock
241
+ self._cycles_to_frame = (FRAME_CYCLES - self.clock) << self.speed_shift
241
242
  return interrupt_flag
242
243
 
243
244
  def save_state(self, f):
@@ -337,8 +338,9 @@ class LCD:
337
338
  self.last_cycles = f.read_64bit()
338
339
  self.clock = f.read_64bit()
339
340
  self.clock_target = f.read_64bit()
340
- self._cycles_to_interrupt = self.clock_target - self.clock
341
- self._cycles_to_frame = (FRAME_CYCLES << self.speed_shift) - self.clock
341
+ # NOTE: speed_shift because they are using in externally in mb
342
+ self._cycles_to_interrupt = (self.clock_target - self.clock) << self.speed_shift
343
+ self._cycles_to_frame = (FRAME_CYCLES - self.clock) << self.speed_shift
342
344
  self.next_stat_mode = f.read()
343
345
 
344
346
  if self.cgb:
@@ -13,6 +13,7 @@ cimport pyboy.core.cpu
13
13
  cimport pyboy.core.interaction
14
14
  cimport pyboy.core.lcd
15
15
  cimport pyboy.core.ram
16
+ cimport pyboy.core.serial
16
17
  cimport pyboy.core.sound
17
18
  cimport pyboy.core.timer
18
19
  from pyboy.logging.logging cimport Logger
@@ -23,7 +24,7 @@ cdef Logger logger
23
24
 
24
25
  cdef int64_t MAX_CYCLES
25
26
  cdef uint16_t STAT, LY, LYC
26
- cdef int INTR_TIMER, INTR_HIGHTOLOW
27
+ cdef int INTR_TIMER, INTR_SERIAL, INTR_HIGHTOLOW
27
28
  cdef uint16_t OPCODE_BRK
28
29
  cdef int STATE_VERSION
29
30
 
@@ -35,6 +36,7 @@ cdef class Motherboard:
35
36
  cdef pyboy.core.lcd.LCD lcd
36
37
  cdef pyboy.core.cpu.CPU cpu
37
38
  cdef pyboy.core.timer.Timer timer
39
+ cdef pyboy.core.serial.Serial serial
38
40
  cdef pyboy.core.sound.Sound sound
39
41
  cdef pyboy.core.cartridge.base_mbc.BaseMBC cartridge
40
42
  cdef bint bootrom_enabled
@@ -9,14 +9,15 @@ from pyboy.utils import (
9
9
  PyBoyException,
10
10
  PyBoyOutOfBoundsException,
11
11
  INTR_TIMER,
12
+ INTR_SERIAL,
12
13
  INTR_HIGHTOLOW,
13
14
  OPCODE_BRK,
15
+ MAX_CYCLES,
14
16
  )
15
17
 
16
- from . import bootrom, cartridge, cpu, interaction, lcd, ram, sound, timer
18
+ from . import bootrom, cartridge, cpu, interaction, lcd, ram, serial, sound, timer
17
19
 
18
20
  logger = pyboy.logging.get_logger(__name__)
19
- MAX_CYCLES = 1 << 31
20
21
 
21
22
 
22
23
  class Motherboard:
@@ -48,6 +49,7 @@ class Motherboard:
48
49
  logger.debug("Cartridge type auto-detected to %s", ("CGB" if self.cartridge.cgb else "DMG"))
49
50
 
50
51
  self.timer = timer.Timer()
52
+ self.serial = serial.Serial()
51
53
  self.interaction = interaction.Interaction()
52
54
  self.ram = ram.RAM(cgb, randomize=randomize)
53
55
  self.cpu = cpu.CPU(self)
@@ -95,7 +97,9 @@ class Motherboard:
95
97
  bit0 = self.key1 & 0b1
96
98
  if bit0 == 1:
97
99
  self.double_speed = not self.double_speed
100
+ self.lcd.tick(self.cpu.cycles)
98
101
  self.lcd.speed_shift = 1 if self.double_speed else 0
102
+ self.sound.tick(self.cpu.cycles)
99
103
  self.sound.speed_shift = 1 if self.double_speed else 0
100
104
  logger.debug("CGB double speed is now: %d", self.double_speed)
101
105
  self.key1 ^= 0b10000001
@@ -244,6 +248,7 @@ class Motherboard:
244
248
  self.timer.save_state(f)
245
249
  self.cartridge.save_state(f)
246
250
  self.interaction.save_state(f)
251
+ self.serial.save_state(f)
247
252
  f.flush()
248
253
  logger.debug("State saved.")
249
254
 
@@ -289,6 +294,8 @@ class Motherboard:
289
294
  self.timer.load_state(f, state_version)
290
295
  self.cartridge.load_state(f, state_version)
291
296
  self.interaction.load_state(f, state_version)
297
+ if state_version >= 15:
298
+ self.serial.load_state(f, state_version)
292
299
  f.flush()
293
300
  logger.debug("State loaded.")
294
301
 
@@ -321,7 +328,7 @@ class Motherboard:
321
328
  self.lcd._cycles_to_interrupt, # TODO: Be more agreesive. Only if actual interrupt enabled.
322
329
  self.lcd._cycles_to_frame,
323
330
  self.sound._cycles_to_interrupt,
324
- # self.serial.cycles_to_interrupt(),
331
+ self.serial._cycles_to_interrupt,
325
332
  mode0_cycles,
326
333
  ),
327
334
  )
@@ -334,6 +341,9 @@ class Motherboard:
334
341
 
335
342
  self.sound.tick(self.cpu.cycles)
336
343
 
344
+ if self.serial.tick(self.cpu.cycles):
345
+ self.cpu.set_interruptflag(INTR_SERIAL)
346
+
337
347
  if self.timer.tick(self.cpu.cycles):
338
348
  self.cpu.set_interruptflag(INTR_TIMER)
339
349
 
@@ -380,7 +390,14 @@ class Motherboard:
380
390
  elif 0xFEA0 <= i < 0xFF00: # Empty but unusable for I/O
381
391
  return self.ram.non_io_internal_ram0[i - 0xFEA0]
382
392
  elif 0xFF00 <= i < 0xFF4C: # I/O ports
383
- if 0xFF04 <= i <= 0xFF07:
393
+ if 0xFF01 <= i <= 0xFF02:
394
+ if self.serial.tick(self.cpu.cycles):
395
+ self.cpu.set_interruptflag(INTR_SERIAL)
396
+ if i == 0xFF01:
397
+ return self.serial.SB
398
+ elif i == 0xFF02:
399
+ return self.serial.SC
400
+ elif 0xFF04 <= i <= 0xFF07:
384
401
  if self.timer.tick(self.cpu.cycles):
385
402
  self.cpu.set_interruptflag(INTR_TIMER)
386
403
 
@@ -510,11 +527,16 @@ class Motherboard:
510
527
  elif 0xFF00 <= i < 0xFF4C: # I/O ports
511
528
  if i == 0xFF00:
512
529
  self.ram.io_ports[i - 0xFF00] = self.interaction.pull(value)
513
- elif i == 0xFF01:
514
- self.serialbuffer[self.serialbuffer_count] = value
515
- self.serialbuffer_count += 1
516
- self.serialbuffer_count &= 0x3FF
517
- self.ram.io_ports[i - 0xFF00] = value
530
+ elif 0xFF01 <= i <= 0xFF02:
531
+ if self.serial.tick(self.cpu.cycles):
532
+ self.cpu.set_interruptflag(INTR_SERIAL)
533
+ if i == 0xFF01:
534
+ self.serialbuffer[self.serialbuffer_count] = value
535
+ self.serialbuffer_count += 1
536
+ self.serialbuffer_count &= 0x3FF
537
+ self.serial.set_SB(value)
538
+ elif i == 0xFF02:
539
+ self.serial.set_SC(value)
518
540
  elif 0xFF04 <= i <= 0xFF07:
519
541
  if self.timer.tick(self.cpu.cycles):
520
542
  self.cpu.set_interruptflag(INTR_TIMER)
@@ -4,11 +4,12 @@
4
4
  #
5
5
 
6
6
  cimport cython
7
- from libc.stdint cimport uint8_t
7
+ from libc.stdint cimport uint8_t, uint16_t
8
8
 
9
9
  from pyboy.logging.logging cimport Logger
10
10
  from pyboy.utils cimport IntIOInterface
11
11
 
12
+ cdef uint16_t INTERNAL_RAM0, INTERNAL_RAM0_CGB, NON_IO_INTERNAL_RAM0, IO_PORTS, NON_IO_INTERNAL_RAM1, INTERNAL_RAM1
12
13
 
13
14
  cdef Logger logger
14
15
 
@@ -0,0 +1,29 @@
1
+ #
2
+ # License: See LICENSE.md file
3
+ # GitHub: https://github.com/Baekalfen/PyBoy
4
+ #
5
+
6
+ from libc.stdint cimport int64_t, uint8_t, uint16_t, uint32_t, uint64_t
7
+
8
+ from pyboy.utils cimport IntIOInterface
9
+
10
+ import cython
11
+
12
+ from pyboy.logging.logging cimport Logger
13
+
14
+ cdef uint64_t MAX_CYCLES, CYCLES_8192HZ
15
+ cdef Logger logger
16
+
17
+ cdef class Serial:
18
+ cdef uint64_t SB, SC
19
+ cdef int64_t _cycles_to_interrupt
20
+ cdef uint64_t last_cycles, clock, clock_target
21
+ cdef bint transfer_enabled, double_speed, internal_clock
22
+
23
+ cdef bint tick(self, uint64_t) noexcept nogil
24
+
25
+ cdef void set_SB(self, uint8_t) noexcept nogil
26
+ cdef void set_SC(self, uint8_t) noexcept nogil
27
+
28
+ cdef int save_state(self, IntIOInterface) except -1
29
+ cdef int load_state(self, IntIOInterface, int) except -1
@@ -0,0 +1,78 @@
1
+ #
2
+ # License: See LICENSE.md file
3
+ # GitHub: https://github.com/Baekalfen/PyBoy
4
+ #
5
+
6
+ from pyboy.utils import MAX_CYCLES
7
+
8
+ CYCLES_8192HZ = 128
9
+
10
+
11
+ class Serial:
12
+ def __init__(self):
13
+ self.SB = 0xFF # Always 0xFF for a disconnected link cable
14
+ self.SC = 0
15
+ self.transfer_enabled = 0
16
+ self.internal_clock = 0
17
+ self._cycles_to_interrupt = 0
18
+ self.last_cycles = 0
19
+ self.clock = 0
20
+ self.clock_target = MAX_CYCLES
21
+
22
+ def set_SB(self, value):
23
+ # Always 0xFF when cable is disconnected. Connecting is not implemented yet.
24
+ self.SB = 0xFF
25
+
26
+ def set_SC(self, value): # cgb, double_speed
27
+ self.SC = value
28
+ self.transfer_enabled = self.SC & 0x80
29
+ # TODO:
30
+ # if cgb and (self.SC & 0b10): # High speed transfer
31
+ # self.double_speed = ...
32
+ self.internal_clock = self.SC & 1 # 0: external, 1: internal
33
+ if self.internal_clock:
34
+ self.clock_target = self.clock + 8 * CYCLES_8192HZ
35
+ else:
36
+ # Will never complete, as there is no connection
37
+ self.transfer_enabled = 0 # Technically it is enabled, but no reason to track it.
38
+ self.clock_target = MAX_CYCLES
39
+ self._cycles_to_interrupt = self.clock_target - self.clock
40
+
41
+ def tick(self, _cycles):
42
+ cycles = _cycles - self.last_cycles
43
+ if cycles == 0:
44
+ return False
45
+ self.last_cycles = _cycles
46
+
47
+ self.clock += cycles
48
+
49
+ interrupt = False
50
+ if self.transfer_enabled and self.clock >= self.clock_target:
51
+ self.SC &= 0x80
52
+ self.transfer_enabled = 0
53
+ # self._cycles_to_interrupt = MAX_CYCLES
54
+ self.clock_target = MAX_CYCLES
55
+ interrupt = True
56
+
57
+ self._cycles_to_interrupt = self.clock_target - self.clock
58
+ return interrupt
59
+
60
+ def save_state(self, f):
61
+ f.write(self.SB)
62
+ f.write(self.SC)
63
+ f.write(self.transfer_enabled)
64
+ f.write(self.internal_clock)
65
+ f.write_64bit(self.last_cycles)
66
+ f.write_64bit(self._cycles_to_interrupt)
67
+ f.write_64bit(self.clock)
68
+ f.write_64bit(self.clock_target)
69
+
70
+ def load_state(self, f, state_version):
71
+ self.SB = f.read()
72
+ self.SC = f.read()
73
+ self.transfer_enabled = f.read()
74
+ self.internal_clock = f.read()
75
+ self.last_cycles = f.read_64bit()
76
+ self._cycles_to_interrupt = f.read_64bit()
77
+ self.clock = f.read_64bit()
78
+ self.clock_target = f.read_64bit()
@@ -10,7 +10,7 @@ from pyboy.logging.logging cimport Logger
10
10
  from pyboy.utils cimport IntIOInterface, double_to_uint64_ceil
11
11
 
12
12
  cdef int FRAME_CYCLES
13
-
13
+ cdef uint64_t MAX_CYCLES
14
14
 
15
15
  cdef Logger logger
16
16
 
@@ -59,7 +59,7 @@ cdef class Sound:
59
59
  cdef uint8_t get(self, uint8_t) noexcept nogil
60
60
  cdef void set(self, uint8_t, uint8_t) noexcept nogil
61
61
 
62
- @cython.locals(cycles=uint64_t)
62
+ @cython.locals(cycles=uint64_t, _cycles=uint64_t)
63
63
  cdef void tick(self, uint64_t) noexcept nogil
64
64
  cdef void sample(self) noexcept nogil
65
65
  cdef uint8_t pcm12(self) noexcept nogil