├── .github
└── workflows
│ └── pages.yml
├── .gitignore
├── LICENSE-CC0.txt
├── README.md
├── book.toml
├── content
├── SUMMARY.md
├── ack.md
├── audio
│ ├── directsound.md
│ ├── images
│ │ ├── chan3wavstop.gif
│ │ ├── demo3.gif
│ │ ├── demos1.gif
│ │ ├── envelope.gif
│ │ ├── lfsr.gif
│ │ ├── lfsroutput.gif
│ │ ├── sound3reset.gif
│ │ ├── sweeps.gif
│ │ └── waveduty.gif
│ ├── introduction.md
│ ├── registers.md
│ ├── sound1.md
│ ├── sound2.md
│ ├── sound3.md
│ └── sound4.md
├── backgrounds.md
├── bios.md
├── bootleg-carts
│ ├── images
│ │ ├── back.jpg
│ │ ├── chips.jpg
│ │ ├── commands.png
│ │ ├── flashers.jpg
│ │ ├── label-removal.jpg
│ │ ├── label.jpg
│ │ └── regions.png
│ └── introduction.md
├── cpu.md
├── fixed-point-math.md
├── fonts
│ └── interweb
│ │ ├── Inter-Black.woff
│ │ ├── Inter-Black.woff2
│ │ ├── Inter-BlackItalic.woff
│ │ ├── Inter-BlackItalic.woff2
│ │ ├── Inter-Bold.woff
│ │ ├── Inter-Bold.woff2
│ │ ├── Inter-BoldItalic.woff
│ │ ├── Inter-BoldItalic.woff2
│ │ ├── Inter-ExtraBold.woff
│ │ ├── Inter-ExtraBold.woff2
│ │ ├── Inter-ExtraBoldItalic.woff
│ │ ├── Inter-ExtraBoldItalic.woff2
│ │ ├── Inter-ExtraLight.woff
│ │ ├── Inter-ExtraLight.woff2
│ │ ├── Inter-ExtraLightItalic.woff
│ │ ├── Inter-ExtraLightItalic.woff2
│ │ ├── Inter-Italic.woff
│ │ ├── Inter-Italic.woff2
│ │ ├── Inter-Light.woff
│ │ ├── Inter-Light.woff2
│ │ ├── Inter-LightItalic.woff
│ │ ├── Inter-LightItalic.woff2
│ │ ├── Inter-Medium.woff
│ │ ├── Inter-Medium.woff2
│ │ ├── Inter-MediumItalic.woff
│ │ ├── Inter-MediumItalic.woff2
│ │ ├── Inter-Regular.woff
│ │ ├── Inter-Regular.woff2
│ │ ├── Inter-SemiBold.woff
│ │ ├── Inter-SemiBold.woff2
│ │ ├── Inter-SemiBoldItalic.woff
│ │ ├── Inter-SemiBoldItalic.woff2
│ │ ├── Inter-Thin.woff
│ │ ├── Inter-Thin.woff2
│ │ ├── Inter-ThinItalic.woff
│ │ ├── Inter-ThinItalic.woff2
│ │ ├── Inter-italic.var.woff2
│ │ ├── Inter-roman.var.woff2
│ │ ├── Inter.var.woff2
│ │ ├── LICENSE.txt
│ │ └── inter.css
├── graphics.md
├── interrupts.md
├── intro.md
├── memory.md
├── overview.md
├── registers.md
├── sprites.md
└── windowing.md
└── theme
├── css
└── general.css
└── head.hbs
/.github/workflows/pages.yml:
--------------------------------------------------------------------------------
1 |
2 | name: Github Pages
3 |
4 | on:
5 | push:
6 | branches:
7 | - main
8 |
9 | jobs:
10 | build:
11 | runs-on: ubuntu-latest
12 |
13 | steps:
14 | - name: Checkout Repository
15 | uses: actions/checkout@v2
16 | with:
17 | # github-pages-deploy-action requires we set this
18 | persist-credentials: false
19 |
20 | # Note(Lokathor): it may seem silly to install
21 | # rust and build the mdbook binary from scratch,
22 | # but it only takes 5 minutes total, which isn't a very
23 | # big deal to wait after a merge.
24 |
25 | - name: Install Rust
26 | uses: actions-rs/toolchain@v1
27 | with:
28 | toolchain: stable
29 | profile: minimal
30 | default: true
31 |
32 | - name: Install mdbook
33 | run: cargo install mdbook
34 |
35 | - name: Build the book
36 | run: mdbook build
37 |
38 | - name: Deploy to GitHub Pages
39 | uses: JamesIves/github-pages-deploy-action@3.7.1
40 | with:
41 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
42 | BRANCH: gh-pages
43 | FOLDER: target/book
44 | force_orphan: true
45 | CLEAN: true
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /target/
2 |
3 | # random crap that tends to appear over time
4 | Thumbs.db
5 | .DS_Store
6 | .DS_Store?
7 | *.bak
8 | *~
9 | *#
10 | *.orig
11 | desktop.ini
12 | *.swp
13 |
--------------------------------------------------------------------------------
/LICENSE-CC0.txt:
--------------------------------------------------------------------------------
1 | CC0 1.0 Universal
2 |
3 | Statement of Purpose
4 |
5 | The laws of most jurisdictions throughout the world automatically confer
6 | exclusive Copyright and Related Rights (defined below) upon the creator and
7 | subsequent owner(s) (each and all, an "owner") of an original work of
8 | authorship and/or a database (each, a "Work").
9 |
10 | Certain owners wish to permanently relinquish those rights to a Work for the
11 | purpose of contributing to a commons of creative, cultural and scientific
12 | works ("Commons") that the public can reliably and without fear of later
13 | claims of infringement build upon, modify, incorporate in other works, reuse
14 | and redistribute as freely as possible in any form whatsoever and for any
15 | purposes, including without limitation commercial purposes. These owners may
16 | contribute to the Commons to promote the ideal of a free culture and the
17 | further production of creative, cultural and scientific works, or to gain
18 | reputation or greater distribution for their Work in part through the use and
19 | efforts of others.
20 |
21 | For these and/or other purposes and motivations, and without any expectation
22 | of additional consideration or compensation, the person associating CC0 with a
23 | Work (the "Affirmer"), to the extent that he or she is an owner of Copyright
24 | and Related Rights in the Work, voluntarily elects to apply CC0 to the Work
25 | and publicly distribute the Work under its terms, with knowledge of his or her
26 | Copyright and Related Rights in the Work and the meaning and intended legal
27 | effect of CC0 on those rights.
28 |
29 | 1. Copyright and Related Rights. A Work made available under CC0 may be
30 | protected by copyright and related or neighboring rights ("Copyright and
31 | Related Rights"). Copyright and Related Rights include, but are not limited
32 | to, the following:
33 |
34 | i. the right to reproduce, adapt, distribute, perform, display, communicate,
35 | and translate a Work;
36 |
37 | ii. moral rights retained by the original author(s) and/or performer(s);
38 |
39 | iii. publicity and privacy rights pertaining to a person's image or likeness
40 | depicted in a Work;
41 |
42 | iv. rights protecting against unfair competition in regards to a Work,
43 | subject to the limitations in paragraph 4(a), below;
44 |
45 | v. rights protecting the extraction, dissemination, use and reuse of data in
46 | a Work;
47 |
48 | vi. database rights (such as those arising under Directive 96/9/EC of the
49 | European Parliament and of the Council of 11 March 1996 on the legal
50 | protection of databases, and under any national implementation thereof,
51 | including any amended or successor version of such directive); and
52 |
53 | vii. other similar, equivalent or corresponding rights throughout the world
54 | based on applicable law or treaty, and any national implementations thereof.
55 |
56 | 2. Waiver. To the greatest extent permitted by, but not in contravention of,
57 | applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and
58 | unconditionally waives, abandons, and surrenders all of Affirmer's Copyright
59 | and Related Rights and associated claims and causes of action, whether now
60 | known or unknown (including existing as well as future claims and causes of
61 | action), in the Work (i) in all territories worldwide, (ii) for the maximum
62 | duration provided by applicable law or treaty (including future time
63 | extensions), (iii) in any current or future medium and for any number of
64 | copies, and (iv) for any purpose whatsoever, including without limitation
65 | commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes
66 | the Waiver for the benefit of each member of the public at large and to the
67 | detriment of Affirmer's heirs and successors, fully intending that such Waiver
68 | shall not be subject to revocation, rescission, cancellation, termination, or
69 | any other legal or equitable action to disrupt the quiet enjoyment of the Work
70 | by the public as contemplated by Affirmer's express Statement of Purpose.
71 |
72 | 3. Public License Fallback. Should any part of the Waiver for any reason be
73 | judged legally invalid or ineffective under applicable law, then the Waiver
74 | shall be preserved to the maximum extent permitted taking into account
75 | Affirmer's express Statement of Purpose. In addition, to the extent the Waiver
76 | is so judged Affirmer hereby grants to each affected person a royalty-free,
77 | non transferable, non sublicensable, non exclusive, irrevocable and
78 | unconditional license to exercise Affirmer's Copyright and Related Rights in
79 | the Work (i) in all territories worldwide, (ii) for the maximum duration
80 | provided by applicable law or treaty (including future time extensions), (iii)
81 | in any current or future medium and for any number of copies, and (iv) for any
82 | purpose whatsoever, including without limitation commercial, advertising or
83 | promotional purposes (the "License"). The License shall be deemed effective as
84 | of the date CC0 was applied by Affirmer to the Work. Should any part of the
85 | License for any reason be judged legally invalid or ineffective under
86 | applicable law, such partial invalidity or ineffectiveness shall not
87 | invalidate the remainder of the License, and in such case Affirmer hereby
88 | affirms that he or she will not (i) exercise any of his or her remaining
89 | Copyright and Related Rights in the Work or (ii) assert any associated claims
90 | and causes of action with respect to the Work, in either case contrary to
91 | Affirmer's express Statement of Purpose.
92 |
93 | 4. Limitations and Disclaimers.
94 |
95 | a. No trademark or patent rights held by Affirmer are waived, abandoned,
96 | surrendered, licensed or otherwise affected by this document.
97 |
98 | b. Affirmer offers the Work as-is and makes no representations or warranties
99 | of any kind concerning the Work, express, implied, statutory or otherwise,
100 | including without limitation warranties of title, merchantability, fitness
101 | for a particular purpose, non infringement, or the absence of latent or
102 | other defects, accuracy, or the present or absence of errors, whether or not
103 | discoverable, all to the greatest extent permissible under applicable law.
104 |
105 | c. Affirmer disclaims responsibility for clearing rights of other persons
106 | that may apply to the Work or any use thereof, including without limitation
107 | any person's Copyright and Related Rights in the Work. Further, Affirmer
108 | disclaims responsibility for obtaining any necessary consents, permissions
109 | or other rights required for any use of the Work.
110 |
111 | d. Affirmer understands and acknowledges that Creative Commons is not a
112 | party to this document and has no duty or obligation with respect to this
113 | CC0 or use of the Work.
114 |
115 | For more information, please see
116 | Mode bits. These indicate the current processor mode: `10000` - User mode Size of the sprite. The top two bits of the size value are found in [attribute 0](#attr0) and the bottom two bits are in attribute 1. This forms a 4-bit value which sets the size of the sprite in the following way:
00=9bit at 32768 Hz
01= 8bit at 65536 Hz
10=7bit at 131072 Hz
11= 6bit at 262144 Hz | RW |
116 |
117 | _Notes_
118 |
119 | 1. The BIAS setting is used to offset the sound output and bring it back into a signed range. When the BIOS starts up, it runs a timing loop where it slowly raises the BIAS voltage from 0 to 512. This setting should not be changed. At best, the sound will become distorted. At worst the amplifier inside the GBA could be damaged. When accessing bits FE, a read-modify-write is required.
120 | 2. The default value for bits FE is 00. Most if not all games, uses 01 for this setting. More research is being done on this register.
121 |
122 | ## DirectSound FIFO A
123 |
124 | | Offset | Name |
125 | | ----------- | ---------- |
126 | | 0x0A0-0x0A2 | REG_FIFO_A |
127 |
128 | ### 0x0A0
129 |
130 | | Bit(s) | Effect | Access |
131 | | ------ | -------------- | ------ |
132 | | 7-0 | 8-Bit sample 0 | W |
133 | | F-8 | 8-Bit sample 1 | W |
134 |
135 | ### 0x0A2
136 |
137 | | Bit(s) | Effect | Access |
138 | | ------ | -------------- | ------ |
139 | | 7-0 | 8-Bit sample 2 | W |
140 | | F-8 | 8-Bit sample 3 | W |
141 |
142 | _Notes_
143 |
144 | 1. These registers contains the samples required for Direct Sound channel A output.
145 | 2. Reading from this register yields unpredictable results.
146 |
147 | ## DirectSound FIFO B
148 |
149 | | Offset | Name |
150 | | ----------- | ---------- |
151 | | 0x0A4-0x0A6 | REG_FIFO_B |
152 |
153 | ### 0x0A4
154 |
155 | | Bit(s) | Effect | Access |
156 | | ------ | -------------- | ------ |
157 | | 7-0 | 8-Bit sample 0 | W |
158 | | F-8 | 8-Bit sample 1 | W |
159 |
160 | ### 0x0A6
161 |
162 | | Bit(s) | Effect | Access |
163 | | ------ | -------------- | ------ |
164 | | 7-0 | 8-Bit sample 2 | W |
165 | | F-8 | 8-Bit sample 3 | W |
166 |
167 | _Notes_
168 |
169 | 1. These registers contains the samples required for Direct Sound channel B output.
170 | 2. Reading from this register yields unpredictable results.
171 |
172 | ## DMG Channel 1 Sweep control
173 |
174 | | Offset | Name |
175 | | ------ | --------------- |
176 | | 0x60 | REG_SOUND1CNT_L |
177 |
178 | | Bit(s) | Effect | Access |
179 | | ------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------ |
180 | | 2-0 | Sweep shifts | RW |
181 | | 3 | Sweep increase/decrease:
0=Addition(frequency increases)
1=Subtraction (frequency decreases) | RW |
182 | | 6-4 | Sweep time:
000: Sweep function is off
001: Ts=1 / 128Khz (7.8 ms)
010: Ts=2 / 128Khz (15.6 ms)
011: Ts=3 / 128Khz (23.4 ms)
100: Ts=4 / 128Khz (31.3 ms)
101: Ts=5 / 128Khz (39.1 ms)
110: Ts=6 / 128Khz (46.9 ms)
111: Ts=7 / 128Khz (54.7 ms) | RW |
183 | | F-7 | Unused | |
184 |
185 | _Notes_
186 |
187 | 1. The sound channel 1 produces a square wave with envelope and frequency sweep functions.
188 | 2. This register controls the frequency sweep function. Sweep shifts bits controls the amount of change in frequency (either increase or decrease) at each change. The wave's new period is given by: \\( T = T \pm \frac{T}{2^n} \\) where n is the sweep shifts value.
189 | 3. Sweep time is the delay between sweep shifts. After each delay, frequency changes repeatedly.
190 | 4. When decrementing, if the frequency value gets smaller than zero, the previous value is retained. When incrementing, if the frequency gets greater than the maximum frequency (131Khz or 2048 for the register value) the sound stops.
191 | 5. When the sweep function is not required, set the sweep time to zero and set the increase/decrease bit to 1.
192 | 6. When Initializing the sound (REG_SOUND1CNT_X bit F=1) using sweeps, re-initialize the sound after 8 clocks or more. Otherwise the sound may stop.
193 |
194 | ## DMG Channel 1 Length, Wave Duty and Envelope Control
195 |
196 | | Offset | Name |
197 | | ------ | --------------- |
198 | | 0x062 | REG_SOUND1CNT_H |
199 |
200 | | Bit(s) | Effect | Access |
201 | | ------ | ------------------------------------------------------------------ | ------ |
202 | | 5-0 | Sound length | W |
203 | | 7-6 | Wave duty cycle:
00=12.5%
01=25%
10=50%
11=75% | RW |
204 | | A-8 | Envelope step time | RW |
205 | | B | Envelope mode:
0=Envelope decreases
1=Envelope increases | RW |
206 | | F-C | Initial envelope value | RW |
207 |
208 | _Notes_
209 |
210 | 1. The sound length is an 6 bit value obtained from the following formula: Sound length= (64-register value)\*(1/256) seconds.
211 | 2. After the sound length has been changed, the sound channel must be resetted via bit F of REG_SOUND1CNT_X (when using timed mode).
212 | 3. Wave duty cycle control the percentage of the ON state of the square wave.
213 | 4. The envelope step time is the delay between successive envelope increase or decrease. It is given by the following formula: T=register value\*(1/64) seconds.
214 | 5. Envelope mode control if the envelope is to increase or decrease in volume over time.
215 | 6. The initial volume of the envelope is controlled by bit F-C. 1111 produces the maximum volume and 0000 mutes the sound.
216 |
217 | ## DMG Channel 1 Frequency, Reset and Loop Control
218 |
219 | | Offset | Name |
220 | | ------ | --------------- |
221 | | 0x064 | REG_SOUND1CNT_X |
222 |
223 | | Bit(s) | Effect | Access |
224 | | ------ | -------------------------------------- | ------ |
225 | | A-0 | Sound frequency | W |
226 | | D-B | Unused | |
227 | | E | Timed mode:
0=continuous, 1=timed | RW |
228 | | F | Sound Reset | W |
229 |
230 | _Notes_
231 |
232 | 1. Frequency can be calculated from the following formula: F(hz)=4194304/(32\*(2048-register value)). The minimum frequency is 64Hz and the maximum is 131Khz.
233 | 2. When Bit E (Timed mode) is set to 0, sound 1 is played continuously regardless of the length data in REG_SOUND1CNT_H. When set to 1, sound is played for that specified length and after that, bit 0 of REG_SOUNDCNT_X is reset.
234 | 3. When bit F is set to 1, the envelope is resetted to its initial value and sound restarts at the specified frequency.
235 | 4. Frequency can always be changed without resetting the sound. However, when in continuous mode, alway set the sound lenght to zero after changing the frequency. Otherwise, the sound may stop.
236 |
237 | ## DMG Channel 2 Length, Wave Duty and Envelope Control
238 |
239 | | Offset | Name |
240 | | ------ | --------------- |
241 | | 0x068 | REG_SOUND2CNT_L |
242 |
243 | | Bit(s) | Effect | Access |
244 | | ------ | ------------------------------------------------------------------ | ------ |
245 | | 5-0 | Sound length | W |
246 | | 7-6 | Wave duty cycle:
00=12.5%
01=25%
10=50%
11=75% | RW |
247 | | A-8 | Envelope step time | RW |
248 | | B | Envelope mode:
0=Envelope decreases
1=Envelope increases | RW |
249 | | F-C | Initial envelope value | RW |
250 |
251 | _Notes_
252 |
253 | 1. The sound length is an 6 bit value obtained from the following formula: Sound length= (64-register value)\*(1/256) seconds.
254 | 2. After the sound length has been changed, the sound channel must be resetted via bit F of REG_SOUND2CNT_H (when using timed mode).
255 | 3. Wave duty cycle control the percentage of the ON state of the square wave.
256 | 4. The envelope step time is the delay between successive envelope increase or decrease. It is given by the following formula: T=register value\*(1/64) seconds.
257 | 5. Envelope mode control if the envelope is to increase or decrease in volume over time.
258 | 6. The initial volume of the envelope is controlled by bit F-C. 1111 produces the maximum volume and 0000 mutes the sound.
259 |
260 | ## DMG Channel 2 Frequency, Reset and Loop Control
261 |
262 | | Offset | Name |
263 | | ------ | --------------- |
264 | | 0x06C | REG_SOUND2CNT_H |
265 |
266 | | Bit(s) | Effect | Access |
267 | | ------ | -------------------------------------- | ------ |
268 | | A-0 | Sound frequency | W |
269 | | D-B | Unused | |
270 | | E | Timed mode:
0=continuous, 1=timed | RW |
271 | | F | Sound Reset | W |
272 |
273 | _Notes_
274 |
275 | 1. Frequency can be calculated from the following formula: F(Hz)=4194304/(32\*(2048-register value)). The minimum frequency is 64Hz and the maximum is 131Khz.
276 | 2. When Bit E (Timed mode) is set to 0, sound 2 is played continuously regardless of the length data in REG_SOUND2CNT_L. When set to 1, sound is played for that specified length and after that, bit 1 of REG_SOUNDCNT_X is reset.
277 | 3. When bit F is set to 1, the envelope is resetted to its initial value and sound restarts at the specified frequency.
278 | 4. Frequency can always be changed without resetting the sound. However, when in continuous mode, alway set the sound lenght to zero after changing the frequency. Otherwise, the sound may stop.
279 |
280 | ## DMG Channel 3 Enable and Wave RAM Bank Control
281 |
282 | | Offset | Name |
283 | | ------ | --------------- |
284 | | 0x070 | REG_SOUND3CNT_L |
285 |
286 | | Bit(s) | Effect | Access |
287 | | ------ | ---------------------------------------- | ------ |
288 | | 4-0 | Unused | |
289 | | 5 | Bank Mode (0=2x32, 1=1x64) | RW |
290 | | 6 | Bank Select (Non set bank is written to) | RW |
291 | | 7 | Sound Channel 3 output enable | RW |
292 | | F-8 | Unused | |
293 |
294 | _Notes_
295 |
296 | 1. The sound channel 3 is a circuit that can produce an arbitrary wave pattern. Samples are 4 bit, 8 samples per word, and are located in Wave Ram registers from 0x400090 to 0x40009F.
297 | 2. In the Gameboy Advance, the Wave Ram is banked, providing the ability to play a 64 samples pattern or to select between two 32 samples patterns (Bit 5). Sound channel 3 always produces some audio artifacts (distortion) when sound is initialized. Fortunately, switching banks does not require re-initialisation during playback, thus allowing for dynamic reloading of the Wave Ram without generating any distortion.
298 | 3. Bit 6 controls which bank is active for playing/reloading. If set to 0, samples are played from bank 0 and writing to the Wave Ram will store the data in Bank 1 and vice-versa.
299 | 4. When bit 7 is set and Initial flag (Bit 15) from REG_SOUND3CNT_X is set, the wave pattern starts to play.
300 | 5. Both banks of Wave Ram are filled with zero upon initialization of the Gameboy, Bank 0 being selected. So writing to bank 0 implies setting bit 6 to 1 before loading Wave Ram then set it back to 0 to play it. Most emulator currently ignore banks.
301 |
302 | ## DMG Channel 3 Sound Length and Output Level Control
303 |
304 | | Offset | Name |
305 | | ------ | --------------- |
306 | | 0x072 | REG_SOUND3CNT_H |
307 |
308 | | Bit(s) | Effect | Access |
309 | | ------ | -------------------------------------------------------------------------------------- | ------ |
310 | | 7-0 | Sound length | W |
311 | | C-8 | Unused | |
312 | | F-D | Ouput volume ratio:
000=Mute
001=100%
100=75%
010=50%
011=25% | RW |
313 |
314 | _Notes_
315 |
316 | 1. The sound length is an 8 bit value obtained from the following formula: Register=Note length(in seconds)\*256, hence a 1 second maximum and a 3.9 millisecond minimum sound duration.
317 | 2. After the sound length has be changed, the sound channel must be resetted via bit F of REG_SOUND3CNT_H (when using timed mode).
318 |
319 | ## DMG Channel 3 Frequency, Reset and Loop Control
320 |
321 | | Offset | Name |
322 | | ------ | --------------- |
323 | | 0x074 | REG_SOUND3CNT_X |
324 |
325 | | Bit(s) | Effect | Access |
326 | | ------ | -------------------------------------- | ------ |
327 | | A-0 | Sound frequency | W |
328 | | D-B | Unused | |
329 | | E | Timed mode:
0=continuous, 1=timed | RW |
330 | | F | Sound Reset | W |
331 |
332 | _Notes_
333 |
334 | 1. Frequency can be calculated from the following formula: F(Hz)=4194304/(32\*(2048-register value)). The minimum frequency is 64Hz and the maximum is 131Khz.
335 | 2. When Bit E (Timed mode) is set to 0, sound 3 is played continuously regardless of the length data in REG_SOUND3CNT_H. When set to 1, sound is played for that specified length and after that, bit 2 of REG_SOUNDCNT_X is reset.
336 | 3. When bit F is set to 1, sound resets and restarts at the specified frequency. Frequency and sound reset must be performed in a single write since both are write only.
337 | 4. Note that in continuous mode, frequency can be changed without resetting the sound channel. However, when in continuous mode, alway set the sound lenght to zero after changing the frequency. Otherwise, the sound may stop.
338 |
339 | ## DMG Channel 3 Wave RAM Registers
340 |
341 | | Offset | Name |
342 | | ----------- | -------------- |
343 | | 0x090-0x09F | REG_WAVERAM0-3 |
344 |
345 | | Bit(s) | Effect | Access |
346 | | ------ | -------------- | ------ |
347 | | 3-0 | 4-bit sample 0 | RW |
348 | | 7-4 | 4-bit sample 1 | RW |
349 | | B-8 | 4-bit sample 2 | RW |
350 | | F-C | 4-bit sample 3 | RW |
351 |
352 | _Notes_
353 |
354 | 1. Wave ram spans four 32 bit registers.
355 | 2. Take into account that ARM store 32bit words in little-indian format. So if you load REG_WAVERAM0=0x01234567, in reality, the sample played will be 6-7-4-5-2-3-0-1.
356 |
357 | ## DMG Channel 4 Length, Output Level and Envelope Control
358 |
359 | | Offset | Name |
360 | | ------ | --------------- |
361 | | 0x78 | REG_SOUND4CNT_L |
362 |
363 | | Bit(s) | Effect | Access |
364 | | ------ | ------------------------------------------------------------------ | ------ |
365 | | 5-0 | Sound length | W |
366 | | 7-6 | Unused | |
367 | | A-8 | Envelope step time | RW |
368 | | B | Envelope mode:
0=Envelope decreases
1=Envelope increases | RW |
369 | | F-C | Initial envelope value | RW |
370 |
371 | _Notes_
372 |
373 | 1. The sound length is an 6 bit value obtained from the following formula: Sound length= (64-register value)\*(1/256) seconds.
374 | 2. After the sound length has been changed, the sound channel must be resetted via bit F of REG_SOUND4CNT_H (when using timed mode).
375 | 3. The envelope step time is the delay between successive envelope increase or decrease. It is given by the following formula: T=register value\*(1/64) seconds.
376 | 4. Envelope mode control if the envelope is to increase or decrease in volume over time.
377 | 5. The initial volume of the envelope is controlled by bit F-C. 1111 produces the maximum volume and 0000 mutes the sound.
378 |
379 | ## DMG Channel 4 Noise Parameters, Reset and Loop Control
380 |
381 | | Offset | Name |
382 | | ------ | --------------- |
383 | | 0x07C | REG_SOUND4CNT_H |
384 |
385 | | Bit(s) | Effect | Access |
386 | | ------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------ |
387 | | 2-0 | Clock divider frequency (with f=4.194304 Mhz/8)
000: f\*2
001: f
010: f/2
011: f/3
100: f/4
101: f/5
110: f/6
111: f/7 | RW |
388 | | 3 | Counter stages:
0=15 stages, 1=7 stages | RW |
389 | | 7-4 | Counter Pre-Stepper frequency (with Q=clock divider's output frequency):
0000: Q/2
0001: Q/2^2
0010: Q/2^3
0011: Q/2^4
....
1101: Q/2^14
1110: Not used
1111: Not used | RW |
390 | | D-8 | Unused | |
391 | | E | Timed mode:
0=continuous, 1=timed | RW |
392 | | F | Sound Reset | W |
393 |
394 | _Notes_
395 |
396 | 1. Channel 4 produces pseudo-noise generated by a polynomial counter. It is based on a 7/15 stages linear-feedback shift register (LFSR). LFSR counts in a pseudo-random order where each state is generated once and only once during the whole count sequence. The sound is produced by the least significant bit's output stage.
397 | 2. A Clock divider controlled by bits 0-2 divides the CPU frequency. Its output is then fed into the counter's pre-scaler (controlled by bits 4-7) which divides further more the frequency.
398 | 3. The Counter stages controls the period of the polynomial counter. It is given by (2^n)-1 where n=number of stages. So for n=7, the pseudo-noise period lasts 63 input clocks. After that, the counter restarts the same count sequence.
399 | 4. When Bit E (Timed mode) is set to 0, sound 4 is played continuously regardless of the length data in REG_SOUND4CNT_L. When set to 1, sound is played for that specified length and after that, bit 3 of REG_SOUNDCNT_X is reset.
400 | 5. When bit F is set to 1, Envelope is set to initial value, the LFSR count sequence is resetted and the sound restarts.
401 | 6. Note that in continuous mode, all parameters can be changed but sound need to be resetted when modifying the envelope initial volume or the clock divider for changes to take effects.
402 |
403 | ## Acronyms used
404 |
405 | | Acronym | Meaning |
406 | | ------- | -------------------------------------- |
407 | | DAC | Digital-to-Analog Converters |
408 | | DMA | Direct Memory Access |
409 | | DMG | The original gameboy (Dot Matrix Game) |
410 | | FIFO | First-In-First-Out |
411 |
--------------------------------------------------------------------------------
/content/audio/sound1.md:
--------------------------------------------------------------------------------
1 | # Sound Channel 1
2 |
3 | Sound channel 1 produces square waves with variable duty cycle, frequency sweep and envelope functions. It is often referred as a quadrangular wave pattern.
4 |
5 | Frequency sweeps allows "portamento"-like effects where the frequency raises or decreases during playback. The amount of increase or decrease in frequency (or sweep shifts) and the rate at which it occurs (sweep time) is controllable. Frequency sweeps are controlled by REG_SOUND1CNT_L
6 |
7 | Sweep shifts are controlled by bits 0-2 and are calculated with the following formula:
8 |
9 | \\( T = T \pm \frac{T}{2^n} \\) where T = Wave Period and n = Sweep Shifts
10 |
11 | Sweep time (Ts) controls the delay between sweep shifts and is controlled by bits 4-6:
12 |
13 | - 000: Sweep function is off
14 | - 001: Ts=1 / 128Khz (7.8 ms)
15 | - 010: Ts=2 / 128Khz (15.6 ms)
16 | - 011: Ts=3 / 128Khz (23.4 ms)
17 | - 100: Ts=4 / 128Khz (31.3 ms)
18 | - 101: Ts=5 / 128Khz (39.1 ms)
19 | - 110: Ts=6 / 128Khz (46.9 ms)
20 | - 111: Ts=7 / 128Khz (54.7 ms)
21 |
22 | At each sweep shift, frequency can either increase (bit 3=0) or decrease (bit 3=1).
23 |
24 | Next is an example of frequency sweeps when REG_SOUND1CNT_L=0x0079 (sweep shifts=1 and sweep time=54.7 ms) and the initial frequency from REG_SOUND1CNT_X=0x0400 (~128Hz, 7.8 ms period).
25 |
26 | 
27 |
28 | In the above example, frequency decreases gradually. Note that sweep shifts are repeatedly performed until the new value becomes either less than 0 (the previous value is then retained) or, when incrementing, if the new frequency value exceeds the maximum frequency (131Khz or 2048 in register value). In the latter case, the sound would then stop and DMG Sound 1 status bit from REG_SOUNDCNT_X would be reset. When either sweep shifts or sweep time is zero, the frequency remains unchanged. When the sweep function is not required, set sweep shifts and sweep time to zero and set the increase/decrease bit to 1 or otherwise, sometimes, no sound will be played.
29 |
30 | The envelope function allows for fade-ins or fade-outs of the sound. It has a 4-bit resolution so it can produce 16 different amplitude levels (steps). The delay between step change (step time) is controlled by bits 8-10 of REG_SOUND1CNT_H. The duration of one step is given by: T= step time\*(1/64) sec, hence a maximum fade time of ~1.64 seconds. When the step time is 0, the envelope function is disabled.
31 |
32 | Bit 11 of REG_SOUND1CNT_H controls the envelope direction: 0=envelope decreases and 1=envelope increases.
33 |
34 | The initial value of the envelope is stored in bits 12-15 of REG_SOUND1CNT_H. When decreasing, if the volume reaches 0000, the sound is muted. When increasing, if the volume reaches 1111, the envelope function stops and the volume remains at that level.
35 |
36 | 
37 |
38 | Envelope example for REG_SOUND1CNT_H=0x7400
39 |
40 | Sound 1 can be set to either play for a specified duration or continuously. This is controlled by bit 14 of REG_SOUND1CNT_X. When set to 0 (continuous mode), sound is played continuously regardless of the length data in REG_SOUND1CNT_H. When set to 1 (timed mode), sound is played for that specified length and after that the DMG Sound 1 status bit of REG_SOUNDCNT_X is reset.
41 |
42 | The sound length (bits 0-5 of REG_SOUND1CNT_H) is a value obtained from the following formula:
43 |
44 | **Sound length = (64-register value)\*(1/256) seconds**
45 |
46 | When using timed mode, after the sound length has be changed, the sound channel must be resetted via bit 15 of REG_SOUND1CNT_X.
47 |
48 | Frequency (bits 0-10 of REG_SOUND1CNT_X) can be calculated from the following formula:
49 |
50 | **F(Hz) = 4194304/(32\*(2048-register value)). The minimum frequency is 64Hz and the maximum is 131Khz.**
51 |
52 | The duty cycle is the ratio of the duration (time) that a signal is ON versus the total period of the signal. The longer it is ON the greater the duty cycle. Sound channel 1 support 4 different duty cycles, which produces very distinctive sounds. Duty cycle is controlled by bit 6-7 of REG_SOUND1CNT_H.
53 |
54 | Possible duty cycles:
55 |
56 | 
57 |
58 | All parameters can be changed dynamically while the sound is playing. The envelope initial volume parameter does not have any effects (except when set to zero) until the sound is resetted. Also, resetting the sound does not reset the oscillator (i.e.:square wave pattern is continuous) although the period is slightly longer for the cycle generated during reset (usually +~500us).
59 |
60 | ## Sound Channel 1 Demo
61 |
62 | 
63 |
64 | A comprehensive demo is included. It shows all features of sound channel 1. The demo also allows to change the resampling frequency bit contained in REG_SOUNDBIAS. Its effects, at least on channel 1, is admittedly very subtle if not unnoticeable.
65 |
66 | ```C
67 | #include F E D C B A 9 8 7 6 5 4 3 2 1 0
34 | L L L L V H T T T T T T T T T T
35 | 7 6 5 4 3 2 1 0
67 | T T T T T T T T
68 |
69 |
70 | | Bits | Description |
71 | |---------|---------------------------------------------------------|
72 | | 0-7 (T) | The tile number
73 |
74 |
75 | Rotational backgrounds do not divide tile maps into blocks.
76 |
77 |
78 |
79 | * * *
80 |
81 |
82 |
83 | For specific details on the format of background data and map entries, check out the section on [REG_BG0CNT - REG_BG3CNT](registers.md#REG_BGCNT) (addresses `0x04000008` - `0x0400000E`).
84 |
85 | In all modes, up to 128 sprites can be displayed as well as the 4 background layers. These use the second [palette](memory.md#palette-ram) which is located at `0x05000200`. See the [OAM](sprites.md) section for details on how to display sprites.
86 |
87 | Both background tiles and sprites use palette entry 0 as the transparent color. Pixels in this color will not be drawn, and allow other background layers and sprites to show through.
88 |
--------------------------------------------------------------------------------
/content/bios.md:
--------------------------------------------------------------------------------
1 |
2 | # BIOS (Software Interrupts)
3 |
4 | The BIOS calls are basically SWI instructions; the value passed into the instruction tells the CPU which interrupt to execute. There is very little public domain information on the BIOS. Marat Fayzullin has a listing of the BIOS calls on his VGBA website, and Forgotten has added a list to his [Visual Boy Advance FAQ](http://vboy.emuhq.com/faq.shtml). It is using these, in combination with observing the behavior of various demos in CowBite and other emulators that I was able to piece together what I have here.
5 |
6 | ### `0x00`: SoftReset
7 |
8 | Resets the GBA and runs the code at address `0x02000000` or `0x08000000` depending on the contents of `0x03007ffa` (0 means `0x08000000` and anything else means `0x02000000`).
9 |
10 | ### `0x01`: RegisterRamReset
11 |
12 | Performs a selective reset of memory and I/O registers.
13 |
14 | Input: r0 = reset flags
15 |
16 |
17 | ### `0x02`: Halt
18 |
19 | Halts CPU execution until an interrupt occurs.
20 |
21 | ### `0x03`: Stop
22 |
23 | Stops the CPU and LCD until the enabled interrupt (keypad, cartridge or serial) occurs.
24 |
25 | ### `0x04`: IntrWait
26 |
27 | Waits for the given interrupt to happen.
28 |
29 |
30 | Input: r0 = initial flag clear, r1 = interrupt to wait
31 |
32 |
33 | ### `0x05`: VBlankIntrWait
34 |
35 | Waits for vblank to occur. Waits based on interrupt rather than polling in order to save battery power.
36 |
37 | Equivalent of calling IntrWait with r0=1 and r1=1.
38 |
39 | ### `0x06`: Div
40 |
41 |
42 | Input: r0 = numerator, r1 = denominator
43 | Output: r0 = numerator/denominator;
44 | r1 = numerator % denominator;
45 | r3 = abs (numerator/denominator)
46 |
47 |
48 | ### `0x07`: DivArm
49 |
50 |
51 | Input: r0 = denominator, r1 = numerator
52 | Output: r0 = numerator/denominator;
53 | r1 = numerator % denominator;
54 | r3 = abs (numerator/denominator)
55 |
56 |
57 | ### `0x08`: Sqrt
58 |
59 |
60 | Input: r0 = number
61 | Output: r0 = sqrt(number)
62 |
63 |
64 | ### `0x09`: ArcTan
65 |
66 |
67 | Input: r0 = angle (signed 16-bit)
68 | Output: r0 = arctan(angle)
69 |
70 |
71 | ### `0x0A`: ArcTan2
72 |
73 | Calculates the arctangent of the given point.
74 |
75 |
76 | Input: r0 = X (signed 16-bit), r1 = Y (signed 16-bit)
77 | Output: r0 = arctan
78 |
79 |
80 | ### `0x0B`: CPUSet
81 |
82 | Performs a memory transfer.
83 |
84 |
85 | Input: r0 = source address, r1 = dest address
86 | r2 (guess) - formatted like DMA transfer
87 | bit26 = 32 or 16 bit transfer
88 | bits 15 - 0 = number of transfers
89 |
90 |
91 | ### `0x0C`: CPUFastSet
92 |
93 |
94 | Also performs a memory transfer, in 32-bit blocks, presumably with some optimization (and limitations?). I believe the register parameters are set up the same as, or at least similar to, those for CPUSet.
95 |
96 |
97 | ### `0x0D`: BiosChecksum
98 |
99 | Calculates the checksum of the whole BIOS by adding every 32-bit word from the BIOS.
100 |
101 |
102 | Output: r0 = BIOS checksum
103 |
104 |
105 |
106 | ### `0x0E`: BgAffineSet
107 |
108 | Calculates the affine parameters for sprites (rotation and scaling).
109 |
110 |
111 | Input: r0 = source, r1 = dest, r2 = number of calculations, r3 = offset between calculations
112 |
113 |
114 | ### `0x0F`: ObjAffineSet
115 |
116 | ### `0x10`: BitUnPack
117 |
118 | Unpacks bit packed data.
119 |
120 |
121 | Input: r0 = source, r1 = dest, r2 = unpack parameters
122 |
123 |
124 | ### `0x11`: LZ77UnCompWRAM
125 |
126 | Uncompresses LZSS data 8 bits at a time
127 |
128 |
129 | Input: r0 = source address, r1 = dest address
130 |
131 |
132 | ### `0x12`: LZ77UnCompVRAM
133 |
134 | Uncompresses LZSS data 16 bits at a time
135 |
136 |
137 | Input: r0 = source address, r1 = dest address
138 |
139 |
140 | Note: The LZ77 decompressors actually decompress LZSS, not LZ77, which is slightly different. You will have to look on the web to find the algorithm as it is beyond the scope of this document. The following assumes a general famliarity with LZSS.
141 |
142 | On the GBA, the ring buffer or "window" is of size 4096, the minumim compressed length is 3 and the maximum compressed length is 18. Looking into a compressed buffer you will find the size of the uncompressed memory in bytes 2, 3, and 4 (I'm not sure what the first byte does, but it seems to always be set to "01"), followed by the coded data. This is divided up into sections consisting of an 8 bit key followed by a corresponding eight items of varying size. The upper bits in the key correspond to the items with lower addresses and vice versa. For each bit set in the key, the corresponding item will be 16 bits; the top bits four being the number of bytes to output, minus 3, and the bottom sixteen bits being the offset behind the current window position from which to output. For each bit which is not set, the corresponding item is an uncompressed byte and gets sent to the output.
143 |
144 | Thanks to Markus for providing me with some source that helped me figure out all of this.
145 |
146 | ### `0x13`: HuffUnComp
147 |
148 | Unpacks data compressed with Huffman and writes it 32-bits at a time.
149 |
150 |
151 | Input: r0 = source address, r1 = dest address
152 |
153 |
154 | ### `0x14`: RLUnCompWRAM
155 |
156 | Uncompresses RLE data 8 bits at a time
157 |
158 |
159 | Input: r0 = source address, r1 = dest address
160 |
161 |
162 | ### `0x15`: RLUnCompVRAM
163 |
164 | Uncompresses RLE data 16 bits at a time
165 |
166 |
167 | Input: r0 = source address, r1 = dest address
168 |
169 |
170 | ### `0x16`: Diff8bitUnFilterWRAM
171 |
172 | Unpacks data filtered with 8-bit difference and writes it 8-bits at a time.
173 |
174 |
175 | Input: r0 = source, r1 = dest
176 |
177 |
178 | ### `0x17`: Diff8bitUnFilterVRAM
179 |
180 | Unpacks data filtered with 8-bit difference and writes it 16-bits at a time.
181 |
182 |
183 | Input: r0 = source, r1 = dest
184 |
185 |
186 | ### `0x18`: Diff16bitUnFilter
187 |
188 | Unpacks data filtered with 16-bit difference and writes it 16-bits at a time.
189 |
190 |
191 | Input: r0 = source, r1 = dest
192 |
193 |
194 | ### `0x19`: SoundBiasChange
195 |
196 | Sets the sound bias from 0 to 0x200 or from 0x200 to 0 depending on the value of R0.
197 |
198 |
199 | Input: r0 = 0 to set it to 0, other values to set it to 0x200
200 |
201 |
202 | ### `0x1A`: SoundDriverInit
203 |
204 | Initializes the built in sound driver.
205 |
206 |
207 | Input: r0 = SoundArea
208 |
209 |
210 | ### `0x1B`: SoundDriverMode
211 |
212 | Sets the operation of the built in sound driver.
213 |
214 |
215 | Input: r0 = operation mode
216 |
217 |
218 | ### `0x1C`: SoundDriverMain
219 |
220 | Main function of the built in sound driver that is called by applications every VBlank period to render the sound.
221 |
222 | ### `0x1D`: SoundDriverVSync
223 | ### `0x1E`: SoundChannelClear
224 | ### `0x1F`: MIDIKey2Freq
225 | ### `Ox20`: MusicPlayerOpen
226 | ### `0x21`: MusicPlayerStart
227 | ### `0x22`: MusicPlayerStop
228 | ### `0x23`: MusicPlayerContinue
229 | ### `0x24`: MusicPlayerFadeOut
230 | ### `0x25`: MultiBoot
231 | ### `0x26`: ??
232 | ### `0x27`: ??
233 | ### `0x28`: SoundDriverVSyncOff
234 | ### `0x29`: SoundDriverVSyncOn
235 | ### `?`: FIQMasterEnable
--------------------------------------------------------------------------------
/content/bootleg-carts/images/back.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gbadev-org/gbadoc/13f4a26a2925bcc17f21d813188fab57eef2497a/content/bootleg-carts/images/back.jpg
--------------------------------------------------------------------------------
/content/bootleg-carts/images/chips.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gbadev-org/gbadoc/13f4a26a2925bcc17f21d813188fab57eef2497a/content/bootleg-carts/images/chips.jpg
--------------------------------------------------------------------------------
/content/bootleg-carts/images/commands.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gbadev-org/gbadoc/13f4a26a2925bcc17f21d813188fab57eef2497a/content/bootleg-carts/images/commands.png
--------------------------------------------------------------------------------
/content/bootleg-carts/images/flashers.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gbadev-org/gbadoc/13f4a26a2925bcc17f21d813188fab57eef2497a/content/bootleg-carts/images/flashers.jpg
--------------------------------------------------------------------------------
/content/bootleg-carts/images/label-removal.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gbadev-org/gbadoc/13f4a26a2925bcc17f21d813188fab57eef2497a/content/bootleg-carts/images/label-removal.jpg
--------------------------------------------------------------------------------
/content/bootleg-carts/images/label.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gbadev-org/gbadoc/13f4a26a2925bcc17f21d813188fab57eef2497a/content/bootleg-carts/images/label.jpg
--------------------------------------------------------------------------------
/content/bootleg-carts/images/regions.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gbadev-org/gbadoc/13f4a26a2925bcc17f21d813188fab57eef2497a/content/bootleg-carts/images/regions.png
--------------------------------------------------------------------------------
/content/bootleg-carts/introduction.md:
--------------------------------------------------------------------------------
1 | # Bootleg Carts
2 |
3 | Bootleg carts, sometimes called repro carts, are illegal game carts sold from China. At the time of
4 | writing, some members of the GBADev community have purchased them for around $5/cart.
5 |
6 | From discussion with store owners in China, these carts cannot be ordered blank -- they are created
7 | with copywritted games already on them (usually the popular games, Pokemon, Mario, etc).
8 |
9 | However, these carts _can_ be cleaned and overwritten with homebrew games.
10 |
11 | This guide will describe how to develop games for bootleg carts.
12 |
13 | 1. [Size of Carts](#size-of-carts)
14 | 2. [Removing Label](#removing-label)
15 | 3. [Flashing Cart](#flashing-cart)
16 | 4. [Batteryless Saving](#batteryless-saving)
17 | 5. [Hardware Used in Carts](#hardware-used-in-carts)
18 | 6. [Swapping of D0/D1](#swapping-of-d0d1)
19 | 7. [Understanding Commands](#understanding-commands)
20 | 8. [Querying for Information](#querying-for-information)
21 | 9. [Detecting if D0/D1 are Swapped](#detecting-if-d0d1-are-swapped)
22 | 10. [Understanding Region Layout](#understanding-region-layout)
23 | 11. [Erasing a Sector](#erasing-a-sector)
24 | 12. [Saving Data](#saving-data)
25 | 13. [Final Thoughts](#final-thoughts)
26 |
27 | ## Size of Carts
28 |
29 | The carts typically range in size from 4MB to 32MB, with 16MB being the most common.
30 |
31 | If your game requires a lot of storage space, then you will be more restricted in which carts you
32 | can buy.
33 |
34 | For example, _Pokemon_ games come on 16MB carts, and _Kingdom of Hearts - Chain of Memories_ is
35 | 32MB.
36 |
37 | ## Removing Label
38 |
39 | 
40 |
41 | The carts will arrive with illegal content and label. Some carts and cases arrive with scuff marks
42 | as well.
43 |
44 | To remove the label, first take the cart apart. You will need a Y0 screw bit, sometimes called a
45 | gamebit. The [iFixit Moray Driver
46 | Kit](https://www.ifixit.com/Store/Tools/Moray-Driver-Kit/IF145-475) contains one, but they can be
47 | found in lots of places.
48 |
49 | 
50 |
51 | Some products that work with removing labels are [Goo Gone](https://googone.com/) and
52 | [WD-40](https://www.wd40.com/).
53 |
54 | Spray a little bit of the liquid on the label, and wait for it to soak in (Goo Gone takes about
55 | 5min). Then scrap off the label, and wash the plastic with soap and water.
56 |
57 | 
58 |
59 | ## Flashing Cart
60 |
61 | 
62 |
63 | You will need a device to connect the cart to your computer in order to overwrite the contents of
64 | the cart with your game.
65 |
66 | Here are some known flashers at the time of writing:
67 |
68 | * [GBxCart RW](https://shop.insidegadgets.com/product/gbxcart-rw/)
69 | * [Joey Jr](https://bennvenn.myshopify.com/collections/cart-flasher-dumper-reader-writer)
70 | * [GB Operator](https://www.epilogue.co/)
71 |
72 | I personally like GBxCart RW the best because it works on Mac OSX, runs from the command line, and
73 | is [open source](https://github.com/lesserkuma/FlashGBX). To flash your game using GBxCart RW,
74 | after installing FlashGBX on your system, you run:
75 |
76 | ```bash
77 | python3 -m FlashGBX --mode agb --action flash-rom MyGame.gba
78 | ```
79 |
80 | Joey Jr works on Windows and doesn't require any installation, since the cart will show up as an
81 | external drive. You simply drag your game on to the drive in Windows Explorer (or `copy` from the
82 | command line).
83 |
84 | GB Operator has a user interface for playing games off of carts, and is more polished. Writing
85 | games to flash carts is just one feature.
86 |
87 | Your needs may vary, and features may change over time. Buy the best one that works for you, or
88 | buy all of them :-). They're pretty cheap.
89 |
90 | ## Batteryless Saving
91 |
92 | The flashers work because the cart ROMs can be overwritten.
93 |
94 | In the past, carts used to have batteries installed, in order to support SRAM. However, this
95 | increases the cost of manufacturing.
96 |
97 | As of writing, carts are now manufactured without batteries. Typically SRAM is available, but
98 | contents won't persist after power off (so it acts as an 8-bit RAM).
99 |
100 | So how can a game developer make a game that saves player progress?
101 |
102 | By using the same technique that the flashers use - writing data to the ROM itself.
103 |
104 | ## Hardware Used in Carts
105 |
106 | 
107 |
108 | In order to flash data to the cart, you will need to know what chips are in the cart.
109 |
110 | For this guide, I will assume the cart is using a `S29GL128N` chip. You can usually read the chip
111 | by using a magnifying glass and looking at the text stamped on the chip.
112 |
113 | If you are interested in the exact specifications of the chip, you will need to track down the data
114 | sheet for it. [Here is the data sheet for the
115 | S29GL128N](https://github.com/velipso/gvasm/blob/main/mirror/s29glxxxn.pdf). It will tell you
116 | exactly how to communicate with the chip.
117 |
118 | Thankfully, many different chips use the same protocols, so a save routine won't need to know the
119 | exact chip, but instead just a category of chips.
120 |
121 | At a high level, flashing to the cart will consist of:
122 |
123 | 1. Querying the cart for sector layout
124 | 2. Erasing a sector
125 | 3. Writing the data to the sector
126 |
127 | This is accomplished by writing special values to the ROM, at special address locations.
128 |
129 | ## Swapping of D0/D1
130 |
131 | **IMPORTANT NOTE:** Many carts will swap the D0 and D1 lines!
132 |
133 | This means when the specification says you need to write `0x55`, then you actually need to write
134 | `0x56` because bits 0 and 1 are swapped (`01010101` -> `01010110`).
135 |
136 | This also affects reading the sector layout, because the values you read will have bits 0 and 1
137 | swapped as well.
138 |
139 | This _does not_ affect the data written to the ROM. If you want `0x4321` written to memory, then
140 | just write `0x4321`, because it will be swapped on write, and swapped again on read, cancelling it
141 | out.
142 |
143 | ## Understanding Commands
144 |
145 | The table on page 57 shows the different commands available for the `S29GL128N`:
146 |
147 | 
148 |
149 | You can see that this information also exists in the FlashGBX source code, [in the
150 | config](https://github.com/lesserkuma/FlashGBX/blob/9b44a9959bf9fd6bab5f1005ce1c757d2f456fa7/FlashGBX/config/fc_AGB_MSP55LV128M.txt):
151 |
152 | ```javascript
153 | "reset":[
154 | [ 0, 0xF0 ]
155 | ],
156 | "read_identifier":[
157 | [ 0xAAA, 0xA9 ],
158 | [ 0x555, 0x56 ],
159 | [ 0xAAA, 0x90 ]
160 | ],
161 | "read_cfi":[
162 | [ 0xAA, 0x98 ]
163 | ],
164 | ...
165 | ```
166 |
167 | Notice that the "Auto-Select" row doesn't exactly match the `"read_identifier"` information.
168 |
169 | Auto-Select starts with address `0xAAA`, data `0xAA`, but FlashGBX has address `0xAAA`, data
170 | `0xA9` -- this is because D0/D1 are swapped (`10101010` -> `10101001`)! [See the section
171 | above](#swapping-of-d0d1).
172 |
173 | So if we want to perform a reset on the chip, we just write `0xF0` to any address. Note that reset
174 | doesn't _erase_ the chip, it just resets any commands in progress.
175 |
176 | ```c
177 | // reset
178 | *((u16 *)0x08000000) = 0xF0;
179 | __asm("nop");
180 | ```
181 |
182 | The forked goombacolor project from LesserKuma has example code, where [you can see this
183 | happen](https://github.com/lesserkuma/goombacolor/blob/f2bae8eb5087de14008250032c82cf5d294131cd/src/main.c#L585):
184 |
185 | ```c
186 | #define _FLASH_WRITE(pa, pd) { *(((u16 *)AGB_ROM)+((pa)/2)) = pd; __asm("nop"); }
187 |
188 | // reset
189 | _FLASH_WRITE(0, 0xF0);
190 | // auto-select
191 | _FLASH_WRITE(0xAAA, 0xA9);
192 | _FLASH_WRITE(0x555, 0x56);
193 | _FLASH_WRITE(0xAAA, 0x90);
194 | ```
195 |
196 | **IMPORTANT NOTE:** Since we need to control the reads/writes sent to the ROM, we cannot run the
197 | code from the ROM. You will need to [load the code into
198 | EWRAM](https://github.com/lesserkuma/goombacolor/blob/f2bae8eb5087de14008250032c82cf5d294131cd/src/main.c#L553)
199 | or IWRAM so that the bus between the GBA and the cart doesn't have extra reads to execute code.
200 |
201 | ## Querying for Information
202 |
203 | There is a standard protocol used by all flash chips called the [Common Flash Memory
204 | Interface](https://en.wikipedia.org/wiki/Common_Flash_Memory_Interface) (CFI).
205 |
206 | You can use CFI to query a lot of information about the chip you're interacting with. The chip
207 | specifications should have a section on CFI.
208 |
209 | Two things in particular you probably want is whether D0/D1 are swapped, and the region layout.
210 |
211 | ## Detecting if D0/D1 are Swapped
212 |
213 | You can detect if D0/D1 are swapped by putting the chip in CFI mode, then reading the bytes at
214 | `0x20`, `0x22`, and `0x24`. These values are hardcoded to `'Q'`, `'R'`, `'Y'`, but if D0/D1 are
215 | swapped, you'll instead see `'R'`, `'Q'`, `'Z'`.
216 |
217 | Here is some example code:
218 |
219 | ```c
220 | // reset the chip
221 | _FLASH_WRITE(0, 0xF0);
222 | // enter CFI mode
223 | _FLASH_WRITE(0xAA, 0x98);
224 |
225 | // read the header
226 | u16 Q = *(((u16 *)AGB_ROM)+(0x20/2));
227 | u16 R = *(((u16 *)AGB_ROM)+(0x22/2));
228 | u16 Y = *(((u16 *)AGB_ROM)+(0x24/2));
229 | bool swapBits = false;
230 |
231 | if (Q == 'Q' && R == 'R' && Y == 'Y') {
232 | // CFI mode is enabled, D0/D1 are not swapped
233 | swapBits = false;
234 | }
235 | else if (Q == 'R' && R == 'Q' && Y == 'Z') {
236 | // CFI mode is enabled, D0/D1 are swapped
237 | swapBits = true;
238 | }
239 | else {
240 | // chip didn't enter CFI mode, try something else
241 | }
242 | ```
243 |
244 | Once you know if D0/D1 are swapped, you can write a helper function for reading bytes from the ROM:
245 |
246 | ```c
247 | u8 readByte(int addr, bool swapBits) {
248 | u8 data = *(((u16 *)AGB_ROM)+(addr/2));
249 | if (swapBits) {
250 | data =
251 | (data & 0xfc) |
252 | ((data & 1) << 1) |
253 | ((data & 2) >> 1);
254 | }
255 | return data;
256 | }
257 | ```
258 |
259 | ## Understanding Region Layout
260 |
261 | The region layout is useful for calculating where the sectors start, and how large they are.
262 | Assuming you want to overwrite sectors at the end of the ROM, you need to figure out what
263 | address(es) to write to.
264 |
265 | There are 1-4 regions, and each region has a sector count and sector size.
266 |
267 | After entering CFI mode, you can read the region layout from memory:
268 |
269 | 
270 |
271 | Here's some example code:
272 |
273 | ```c
274 | // assuming we are already in CFI mode
275 | int regionCount = readByte(0x58, swapBits);
276 | struct {
277 | int sectorCount;
278 | int sectorSize;
279 | } regions[4] = {0};
280 |
281 | for (int region = 0; region < regionCount; region++) {
282 | int sectorCountLow = readByte(0x5A + region * 8, swapBits);
283 | int sectorCountHigh = readByte(0x5C + region * 8, swapBits);
284 | int sectorSizeLow = readByte(0x5E + region * 8, swapBits);
285 | int sectorSizeHigh = readByte(0x60 + region * 8, swapBits);
286 |
287 | // note we must add one!
288 | regions[region].sectorCount =
289 | ((sectorCountHigh << 8) | sectorCountLow) + 1;
290 |
291 | // note we must multiply by 256!
292 | regions[region].sectorSize =
293 | ((sectorSizeHigh << 8) | sectorSizeLow) << 8;
294 | }
295 | ```
296 |
297 | ## Erasing a Sector
298 |
299 | Erasing a sector will set all the values in that sector to `0xFFFF`.
300 |
301 | This is fairly straight forward, you can use
302 | [goombacolor](https://github.com/lesserkuma/goombacolor/blob/f2bae8eb5087de14008250032c82cf5d294131cd/src/main.c#L657)
303 | as a reference:
304 |
305 | ```c
306 | // Erase flash sector
307 | _FLASH_WRITE(sa, 0xF0);
308 | _FLASH_WRITE(0xAAA, 0xA9);
309 | _FLASH_WRITE(0x555, 0x56);
310 | _FLASH_WRITE(0xAAA, 0x80);
311 | _FLASH_WRITE(0xAAA, 0xA9);
312 | _FLASH_WRITE(0x555, 0x56);
313 | _FLASH_WRITE(sa, 0x30);
314 | while (1) {
315 | __asm("nop");
316 | if (*(((u16 *)AGB_ROM)+(sa/2)) == 0xFFFF) {
317 | break;
318 | }
319 | }
320 | _FLASH_WRITE(sa, 0xF0);
321 | ```
322 |
323 | You now should be able to understand this code.
324 |
325 | This sequence of writes matches the documentation (with D0/D1 swapped).
326 |
327 | The variable `sa` is the sector address. The code:
328 |
329 | 1. Resets the chip
330 | 2. Erases the sector
331 | 3. Waits in a loop until it reads `0xFFFF` from the sector, indicating the erase is finished
332 | 4. Resets the chip again
333 |
334 | ## Saving Data
335 |
336 | Once again, [goombacolor](https://github.com/lesserkuma/goombacolor/blob/f2bae8eb5087de14008250032c82cf5d294131cd/src/main.c#L673)
337 | is a great reference:
338 |
339 | ```c
340 | for (int i=0; i
22 | User/System: 0x03007F00
23 | IRQ: 0x03007FA0
24 | Supervisor: 0x03007FE0
25 |
26 |
27 | As far as I know the other modes do not have default stack pointers.
28 |
29 | * **r14 (LR):** Link Register. Used primarily to store the address following a "bl" (branch and link) instruction (as used in function calls)
30 |
31 | * **r15 (PC):** The Program Counter. Because the ARM7tdmi uses a 3-stage pipeline, this register always contains an address which is 2 instructions ahead of the one currrently being executed. In 32-bit ARM state, it is 8 bytes ahead, while in 16-bit Thumb state it is 4 bytes ahead.
32 |
33 | * **CPSR:** The Current Program Status Register. This contains the status bits relevant to the CPU:
34 |
35 | 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
37 | N Z C V R R R R R R R R R R R R R R R R R R R R I F T M M M M M
40 |
`10001` - FIQ mode
`10010` - IRQ mode
`10011` - Supervisor mode
`10111` - Abort mode
`11011` - Undefined mode
`11111` - System modeF E D C B A 9 8 7 6 5 4 3 2 1 0
52 | X B B B B B G G G G G R R R R R
54 | 0-4 (R) = Red
55 | 5-9 (G) = Green
56 | A-F (B) = Blue
57 |
58 |
--------------------------------------------------------------------------------
/content/interrupts.md:
--------------------------------------------------------------------------------
1 | # Hardware Interrupts
2 |
3 | Figuring out hardware interrupts was kind of painful. Everything below is what I have gleaned from reading [ARM's docs](http://www.arm.com), the list, the advice of other emulator and demo authors, and from various other emulator's debug info. I hope it is of some use to you. Let me know if you find any errors or typos.
4 |
5 | **Key points:**
6 |
7 | All hardware interrupt vectors lie in the BIOS. You cannot handle interrupts directly, you must go through the BIOS. Thus, the instructions for exception handling in the ARM docs do not apply directly since we cannot handle the exceptions directly.
8 |
9 | Interrupts are enabled by setting the flags in the [REG_IE](registers.md#REG_IE) and hardware registers like [REG_DISPSTAT](registers.md#REG_DISPSTAT), [REG_KEYCNT](registers.md#REG_KEYCNT), and [REG_DMAXCNT](registers.md#REG_DMA0CNT). The flag must be set in both REG_IE and the corresponding hardware register for it to work. When the interrupt signal is sent, the appropriate flag is set in [REG_IF](registers.md#REG_IF). The program code unsets this flag (by writing a 1 to that bit) in order to keep track of what interrupts have been handled.
10 |
11 | **When an interrupt occurs, the CPU does the following:**
12 |
13 | 1. Switches state to IRQ mode, bank-swaps the current stack register and link register (thus preserving their old values), saves the CPSR in `SPSR_irq`, and sets bit 7 (interrupt disable) in the CPSR.
14 | 2. Saves the address of the next instruction in `LR_irq` compensating for Thumb/ARM depending on the mode you are in.
15 | 3. Switches to [ARM state](cpu.md#cpu-state), executes code in BIOS at a hardware interrupt vector (which you, the programmer, never see)
16 |
17 | **The BIOS code picks up at the hardware interrupt vector and does the following:**
18 |
19 | 4. Pushes registers `0 - 3`, `12`, `LR_irq` (which cointains the address following the instruction when the interrupt occrued) onto the stack
20 | 5. Places the address for the next instruction (in the BIOS, not in your code) in `LR`
21 | 6. Loads the address found at `0x03007FFC`
22 | 7. Branches to that address.
23 |
24 | **The program code at that address is executed.**
25 |
26 | 8. It is the responsiblity of the code at that address to return once finished, using `BX LR_irq`
27 |
28 | **The BIOS finishes up where your code leaves off:**
29 |
30 | 9. It restores registers `0 - 3`, `12`, `LR_irq`
31 | 10. Branches to the intruction found in `LR`, using a `SUBS PC, LR_irq, #4`
32 |
33 | **Upon receiving the SUBS PC, LR_irq, #4 instruction, the CPU**
34 |
35 | 11. copies the `SPSR_irq` back into the CPSR, restoring the status bits to their state when the interrupt occurred, and bank swaps back in the stack register ad link register. The CPU will thus be placed in the correct state ([ARM](cpu.md#cpu-state) or [Thumb](cpu.md#cpu-state)) it was in when the exception occurred.
36 |
37 |
38 |
39 | So, the basic model for setting up interrupts is:
40 |
41 | 1. Place the address for your interrupt code at `0x03007FFC`.
42 |
43 | 2. Turn on the interrupts you wish to use:
44 |
45 | * [REG_DISPSTAT](registers.md#REG_STAT), [REG_TMXCNT](registers.md#REG_TM0CNT), [REG_KEYCNT](registers.md#REG_KEYCNT), or [REG_DMAXCNT](registers.md#REG_DMA0CNT) tell the hardware which interrupts to send
46 | * `0x04000200` ([REG_IE](registers.md#REG_IE)) masks which interrupts will actually be serviced (?)
47 | * `0x04000208` ([REG_IME](registers.md#REG_IME)) Turns all interrupts on or off.
48 |
49 | 3. When the interrupt is reached, the code at the address at `0x03007FFC` gets loaded into the CPU. To prevent unwanted errors/behavior, the first thing this code should do is disable interrupts.
50 |
51 | 4. To determine what interrupt this is, check the flags in `0x04000202` ([REG_IF](registers.md#REG_IF)). Unset the flag by writing a 1 to that bit.
52 |
53 | 5. Once finished with the service routine, reenable interrupts and execute a `BX LR` (*not* a `SUBS PC, LR #4`, which is what the BIOS does). The BIOS will then take over and return your program to where execution left off.
54 |
55 | ## Types of Hardware Interrupts
56 |
57 | Enable these interrupts using [REG_DISPSTAT](registers.md#REG_STAT), [REG_TMXCNT](registers.md#REG_TM0CNT), [REG_KEYCNT](registers.md#REG_KEYCNT), or [REG_DMAXCNT](registers.md#REG_DMA0CNT), then setting the correct flags in [REG_IE](registers.md#REG_IE) and [REG_IME](registers.md#REG_IME).
58 |
59 | * **V-Blank**: Occurs when the [vcount](registers.md#REG_VCOUNT) reaches 160, or 0xA0. (Enable in [REG_DISPSTAT](registers.md#REG_STAT))
60 |
61 | * **H-Blank**: Occurs at the end of every raster line, from 0 - 228. H-blank interrupts DO occur during v-blank (unlike hdma, which does not), so write your code accordingly. Thanks to gbcft for verifying this. (Enable in [REG_DISPSTAT](registers.md#REG_STAT))
62 |
63 | * **Serial**: I am unsure about this; I presume it has to do with the link cable.
64 |
65 | * **V-Count**: Occurs when the [vcount](registers.md#REG_VCOUNT) reaches the number specified in [REG_DISPSTAT](registers.md#REG_STAT).
66 |
67 | * **Timer**: These occur whenever one of the [timer registers](registers.md#timer-registers) is set to cause an interrupt whenever it overflows. Enable in [REG_TMXCNT](registers.md#REG_TM0CNT).
68 |
69 | * **DMA**: These occur after a DMA transfer, according to the flags in the [DMA_CNT](registers.md#REG_DMA0CNT) registers and in [REG_IE](registers.md#REG_IE). Enable in [REG_DMAXCNT](registers.md#REG_DMA0CNT).
70 |
71 | * **Key**: Occurs when the user presses or releases the buttons specified in [REG_KEYCNT](registers.md#REG_KEYCNT).
72 |
73 | * **Cartridge**: Occurs when the user yanks out or inserts the cartridge out while the GBA is still running. For a cartridge interrupt to work properly the ISR must reside in RAM. It is possible to switch cartridges and have the routine resume execution on a completely different ROM.
74 |
--------------------------------------------------------------------------------
/content/intro.md:
--------------------------------------------------------------------------------
1 | # Introduction
2 |
3 | This is a community effort to provide an open document about the Game Boy Advance (GBA).
4 |
5 | The book is provided to you under the [Creative Commons 0 License](https://creativecommons.org/publicdomain/zero/1.0/legalcode).
6 |
7 | If you'd like to ask questions, report problems, or contribute, then go to our [GitHub Repository](https://github.com/gbdev/gbadoc).
8 |
9 | If you want to just chat about GBA topics you can join the [GBADev Discord](https://discord.io/gbadev).
10 |
11 |
12 | ## The Basics
13 |
14 | From the programmer's perspective, the system is composed of the following:
15 |
16 | * [CPU](cpu.md) - A 16.78 Mhz ARM7tdmi
17 | * [Memory](memory.md) - 8 to 11 distinct areas of memory (depending on the Game Pak).
18 | * [IO](registers.md) - Special hardware functions available to the programmer, primarily pertaining to graphics, sound, DMA, timers, serial communication, key input, and interrupts.
19 |
20 | Programs run on the GBA are usually contained in a "Game Pak". A "Game Pak" consists mainly of [ROM](memory.md#game-pak-rom) and possibly [Cart RAM](memory.md#cart-ram) (in the form of SRAM, Flash ROM, or EEPROM, used mainly for save game info). The ROM is where compiled code and data is stored. Unlike home computers, workstations, or servers, there are no disks or other drives, so everything that might otherwise have been stored as separate resource files must be compiled into the program ROM itself. Luckily there are tools to aid in this process.
21 |
22 | The primary means a program accesses specialized hardware for graphics, sound, and other IO is through the [memory-mapped IO](registers.md). Memory mapped IO is a means of communicating with hardware by writing to/reading from specific memory addresses that are "mapped" to internal hardware functions. For example, you might write to address [0x04000000](registers.md#REG_DISPCNT) with the value "0x0100", which tells the hardware "enable background 0 and graphics mode 0". A secondary means is through the [BIOS](memory.md#system-rom), which is embedded in the internal GBA system ROM. Using [software interrupts](bios.md) it is possible to access pre-programmed (and hopefully optimized) routines lying in the the system ROM. These routines then access the hardware through the memory-mapped IO.
23 |
24 | Other regions of memory that are directly mapped to the hardware are [Palette RAM](memory.md#palette-ram) (which is a table consisting of all the available colors), [VRAM](memory.md#vram) (which performs a similar function to the video RAM on a PC - and thensome), and [OAM](memory.md#oam) (which contains the attributes for hardware accelerated sprites).
25 |
26 | ## Programming for the GBA
27 |
28 | C, C++, and ARM/Thumb assembly are the most common languages used in GBA development, mainly because they are fast and relatively low level (i.e. there is a large degree of correspondance between the structure of the language and underlying instruction set of the architecture).
29 |
30 | The two main development kits are [devkitARM](https://devkitpro.org/) and [gba-toolchain](https://github.com/felixjones/gba-toolchain), but it's also surprisingly easy to [roll your own](https://github.com/AntonioND/gba-bootstrap) using vanilla ARM GCC. Newer systems programming languages such as Rust, D, Nim and Zig are also increasingly used.
31 |
32 | Most GBA programs are structured around the timing of the CPU and graphics hardware. The LCD has a refresh rate of about 59.73 hz, with each refresh consisting of a [vertical draw](graphics.md#VDraw) period (when the GBA is drawing the screen) followed by a [vertical blank](graphics.md#VBlank) period (when nothing is being drawn). The vertical draw and vertical blank periods are further subdivided into [horizontal draw and blank](graphics.md#HDraw) periods. Programs typically use the VBlank and possibly the HBlank periods to update VRAM or graphics hardware registers in order to avoid unwanted visual artifacts, leaving the VDraw and HDraw periods to perform any software processing that will not effect the display. Common methods of syncing to VBlank include polling [REG_DISPSTAT](registers.md#REG_STAT) or [REG_VCOUNT](registers.md#REG_VCOUNT), calling the [VBlankIntrWait](bios.md#0x05-vblankintrwait) BIOS function, or setting up an [interrupt](interrupts.md).
33 |
--------------------------------------------------------------------------------
/content/memory.md:
--------------------------------------------------------------------------------
1 | # Memory
2 |
3 | The following are the general areas of memory as seen by the CPU, and what they are used for.
4 |
5 | ### System ROM
6 |
7 |
8 | Start: 0x00000000
9 | End: 0x00003FFF
10 | Size: 16kb
11 | Port Size: 32 bit
12 | Wait State: 0
13 |
14 |
15 | `0x0` - `0x00003FFF` contain the [BIOS](bios.md), which is executable but not readable. Any attempt to read in the area from `0x0` to `0x1FFFFFFF` will result in failure; what you will see on a read is the current prefetched instruction (the instruction after the instruction used to view the memory area), thus giving the appearance that this area of memory consists of a repeating byte pattern.
16 |
17 | ### External Work RAM
18 |
19 |
20 | Start: 0x02000000
21 | End: 0x0203FFFF
22 | Size: 256kb
23 | Port Size: 16 bit
24 | Mirrors: Every 0x40000 bytes from 0x02000000 to 0x02FFFFFF
25 |
26 |
27 | This space is available for your game's data and code. If a multiboot cable is present on startup, the BIOS automatically detects it and downloads binary code from the cable and places it in this area, and execution begins with the instruction at address `0x02000000` (the default is `0x08000000`). Though this is the largest area of RAM available on the GBA, memory transfers to and from EWRAM are 16 bits wide and thus consume more cycles than necessary for 32 bit accesses. Thus it is advised that 32 bit ARM code be placed in [IWRAM](#internal-work-ram) rather than EWRAM.
28 |
29 | ### Internal Work RAM
30 |
31 |
32 | Start: 0x03000000
33 | End: 0x03007FFF
34 | Size: 32kb
35 | Port Size: 32 bit
36 | Mirrors: Every 0x8000 bytes from 0x03000000 to 0x03FFFFFF
37 |
38 |
39 | This space is also available for use. It is the fastest of all the GBA's RAM, being internally embedded in the ARM7 CPU chip package and having a 32 bit bus. As the bus for [ROM](#game-pak-rom) and [EWRAM](#external-work-ram) is only 16 bits wide, the greatest efficiency will be gained by placing 32 bit ARM code in IWRAM while leaving thumb code for EWRAM or ROM memory.
40 |
41 | ### IO Ram
42 |
43 |
44 | Start: 0x04000000
45 | End: 0x040003FF (0x04010000)
46 | Size: 1Kb
47 | Port Size: Dual ported 32 bit
48 | Mirrors: The word at 0x04000800 (only!) is mirrored every 0x10000 bytes
49 | from 0x04000000 - 0x04FFFFFF.
50 |
51 |
52 | This area contains a mirror of the ASIC (Application Specific Integrated Circuit) registers on the GBA. This area of memory is used to control the graphics, sound, DMA, and other features. See [memory-mapped IO registers](registers.md) for details on the function of each register.
53 |
54 | ### Palette RAM
55 |
56 |
57 | Start: 0x05000000
58 | End: 0x050003FF
59 | Size: 1kb
60 | Port Size: 16 bit
61 | Mirrors: Every 0x400 bytes from 0x05000000 to 0x5FFFFFF
62 |
63 |
64 | This area specifies the [16-bit color](graphics.md#color-format) values for the paletted modes. There are two areas of the palette: one for backgrounds (`0x05000000`) and another for sprites (`0x05000200`). Each of these is either indexed as a single, 256-color palette, or as 16 individual 16-color palettes, depending on the settings of a particular [sprite](sprites.md#attr0) or background.
65 |
66 | ### VRAM
67 |
68 |
69 | Start: 0x06000000
70 | End: 0x06017FFF
71 | Size: 96kb
72 | Port Size: 16 bit
73 | Mirrors: Bytes 0x06010000 - 0x06017FFF is mirrored from 0x06018000 - 0x0601FFFF.
74 | The entire region from 0x06000000 - 0x06020000 is in turn mirrored every
75 | 0x20000 bytes from 0x06000000 - 0x06FFFFFF.
76 |
77 |
78 | The video RAM is used to store the frame buffer in [bitmapped](backgrounds.md#bitmapped-backgrounds) modes, and the tile data and tile maps for tile-based ["text"](backgrounds.md#text-backgrounds) and [rotate/scale](registers.md#background-rotation-scaling-registers) modes.
79 |
80 | ### OAM
81 |
82 |
83 | Start: 0x07000000
84 | End: 0x070003FF
85 | Size: 1kb
86 | Port Size: 32 bit
87 | Mirrors: Every 0x400 bytes from 0x07000000 to 0x07FFFFFF
88 |
89 |
90 | This is the Object Attribute Memory, and is used to control the GBA's [sprites](oam.md).
91 |
92 |
93 |
94 | * * *
95 |
96 |
97 |
98 | The following areas of memory are technically cart-dependent, but can generally be expected to behave as described.
99 |
100 | ### Game Pak ROM
101 |
102 |
103 | Start: 0x08000000
104 | Size: The size of the cartridge (0 - 32 megabytes)
105 | Port Size: 16 bit
106 | Wait State: 0
107 |
108 |
109 | The ROM in the game cartridge appears in this area. If a cartridge is present on startup, the instruction found at location `0x08000000` is loaded into the program counter and execution begins from there. Note that the transfers to and from ROM are all 16 bits wide.
110 |
111 | ### Game Pak ROM Image 1
112 |
113 |
114 | Start: 0x0A000000
115 | Size: The size of the cartridge (0 - 32 megabytes)
116 | Port Size: 16 bit
117 | Wait State: 1
118 |
119 |
120 | This is a mirror of the ROM above. Used to allow multiple speed ROMs in a single game pak.
121 |
122 | ### Game Pak ROM Image 2
123 |
124 |
125 | Start: 0x0C000000
126 | Size: The size of the cartridge (0 - 32 megabytes)
127 | Port Size: 16 bit
128 | Wait State: 2
129 |
130 |
131 | This is a mirror of the ROM above. Used to allow multiple speed ROMs in a single game pak.
132 |
133 | ### Cart RAM
134 |
135 |
136 | Start: 0x0E000000 (also seem to appear at 0x0F000000)
137 | Size: 0 - 64 kb
138 | Port Size: 8 bit
139 |
140 |
141 | This is either SRAM or Flash ROM. Used primarily for saving game data. SRAM can be up to 64kb but is usually 32 kb. It has a battery backup so has the longest life (in terms of how many times it can be written to) of all backup methods. Flash ROM is usually 64 kb. Its lifespan is determined by the number of rewrites that can be done per sector (a 10,000 rewrite minimum is cited by some manufacturers).
142 |
143 | ### EEPROM
144 |
145 | This is another kind of cart memory, but operates differently from SRAM or Flash ROM. Unfortunately, I don't know the details of how it can be accessed by the programmer ([send us a PR](https://github.com/gbadev-org/gbadoc) if you have more information on it). It uses a serial connection to transmit data. The maximum size is 128 mb, but it can be any size, and is usually 4 kb or 64 kb. Like Flash ROM it has a limited life; some manufacturers cite a minimum of 100,000 rewrites per sector.
146 |
147 | There may be other regions of memory known as DEBUG ROM 1 and DEBUG ROM 2, though I really don't know whether these are a part of commercial carts or if they are mapped to some part of the internal ROM, or if they're even available on a standard GBA.
148 |
149 | Note that EWRAM, IWRAM, VRAM, OAM, Palette RAM are all initialized to zero by the BIOS (i.e. you can expect them to be zeroed at startup).
150 |
151 |
--------------------------------------------------------------------------------
/content/overview.md:
--------------------------------------------------------------------------------
1 |
2 | # Overview
3 |
4 | * **CPU:** An [ARM7TDMI](https://en.wikipedia.org/wiki/ARM7#ARM7TDMI) core running
5 | at 16.78 MHz. No floating point unit.
6 | * **Screen:** A 2.9 inch LCD screen with a 240 by 160 resolution.
7 | * **Video:** Runs at approximately 59.72 Hz. Supports tiled graphics in "text" or
8 | "affine" modes, as well as bitmap graphics. 5-bit per channel RGB color.
9 | * **Audio:** Supports 8-bit wave output as well as the legacy Procedural Sound
10 | Generator (PSG) chips from the Game Boy.
11 | * **Input:** Directional pad (up, down, left, right, plus diagonals), four primary
12 | buttons (A, B, L, R), two secondary buttons (Start, Select).
13 | * **Memory:**
14 | * 32k of CPU internal RAM (a small portion of this is pre-allocated)
15 | * 256k of CPU external RAM (totally free for any use)
16 | * 96k of Video RAM (the structure here depends on the video mode)
17 | * 128 Object entries, used to display "sprites".
18 | * 32 Affine parameter entries.
19 | * 256 palette entries for Backgrounds ("backdrop" plus 255 usable colors).
20 | * 256 palette entries for Objects (of which 255 are usable).
21 | * Supports ROMs of up to 32MB in size.
22 | * **Other Peripherals:**
23 | * Serial port that supports up to four devices in the network.
24 | * Four Direct Memory Access (DMA) units. These perform faster memory copies
25 | than the CPU can, and they can be set to automatically activate at
26 | particular times, but the CPU is paused when they are active.
27 | * Four timer units.
28 |
29 | Programs run on the GBA are usually contained in a "Game Pak". A "Game Pak" consists mainly of ROM and possibly Cart RAM (in the form of SRAM, Flash ROM, or EEPROM, used mainly for save game info). The ROM is where compiled code and data is stored. Unlike home computers, workstations, or servers, there are no disks or other drives, so everything that might otherwise have been stored as separate resource files must be compiled into the program ROM itself. Luckily there are tools to aid in this process.
30 |
31 | The primary means a program accesses specialized hardware for graphics, sound, and other IO is through the memory-mapped IO. Memory mapped IO is a means of communicating with hardware by writing to/reading from specific memory addresses that are "mapped" to internal hardware functions. For example, you might write to address 0x04000000 with the value "0x0100", which tells the hardware "enable background 0 and graphics mode 0". A secondary means is through the BIOS, which is embedded in the internal GBA system ROM. Using software interrupts it is possible to access pre-programmed (and hopefully optimized) routines lying in the the system ROM. These routines then access the hardware through the memory-mapped IO.
32 |
33 | Other regions of memory that are directly mapped to the hardware are Palette RAM (which is a table consisting of all the available colors), VRAM (which performs a similar function to the video RAM on a PC - and thensome), and OAM (which contains the attributes for hardware accelerated sprites).
34 |
35 | ## Memory Map
36 |
37 | The following are the general areas of memory as seen by the CPU, and what they are used for.
38 |
39 | ### System ROM (BIOS)
40 |
41 | - Start: 0x00000000
42 | - End: 0x0003FFF
43 | - Size: 16kb
44 | - Port Size: 32 bit
45 | - Wait State: 0
46 |
47 | 0x0 - 0x00003FFF contain the BIOS, which is executable but not readable. Any attempt to read in the area from 0x0 to 0x1FFFFFFF will result in failure; what you will see on a read is the current prefetched instruction (the instruction after the instruction used to view the memory area), thus giving the appearance that this area of memory consists of a repeating byte pattern.
48 |
49 |
50 | ### External Work RAM (EWRAM)
51 |
52 | - Start: 0x02000000
53 | - End: 0x0203FFFF
54 | - Size: 256kb
55 | - Port Size: 16 bit
56 | - Mirrors: Every 0x40000 bytes from 0x02000000 to 0x02FFFFFF
57 |
58 | This space is available for your game's data and code. If a multiboot cable is present on startup, the BIOS automatically detects it and downloads binary code from the cable and places it in this area, and execution begins with the instruction at address 0x02000000 (the default is 0x08000000). Though this is the largest area of RAM available on the GBA, memory transfers to and from EWRAM are 16 bits wide and thus consume more cycles than necessary for 32 bit accesses. Thus it is advised that 32 bit ARM code be placed in IWRAM rather than EWRAM.
59 |
60 |
61 | ### Internal Work RAM (IWRAM)
62 |
63 | - Start: 0x03000000
64 | - End: 0x03007FFF
65 | - Size: 32kb
66 | - Port Size: 32 bit
67 | - Mirrors: Every 0x8000 bytes from 0x03000000 to 0x03FFFFFF
68 |
69 | This space is also available for use. It is the fastest of all the GBA's RAM, being internally embedded in the ARM7 CPU chip package and having a 32 bit bus. As the bus for ROM and EWRAM is only 16 bits wide, the greatest efficiency will be gained by placing 32 bit ARM code in IWRAM while leaving thumb code for EWRAM or ROM memory.
70 |
71 |
72 | ### IO Ram
73 |
74 | - Start: 0x04000000
75 | - End: 0x040003FF (0x04010000)
76 | - Size: 1Kb
77 | - Port Size: Dual ported 32 bit
78 | - Mirrors: The word at 0x04000800 (only!) is mirrored every 0x10000 bytes
79 | from 0x04000000 - 0x04FFFFFF.
80 |
81 | This area contains a mirror of the ASIC (Application Specific Integrated Circuit) registers on the GBA. This area of memory is used to control the graphics, sound, DMA, and other features. See memory-mapped IO registers for details on the function of each register.
82 |
83 |
84 | ### Palette RAM (PALRAM)
85 |
86 | - Start: 0x05000000
87 | - End: 0x050003FF
88 | - Size: 1kb
89 | - Port Size: 16 bit
90 | - Mirrors: Every 0x400 bytes from 0x05000000 to 0x5FFFFFF
91 |
92 | This area specifies the 16-bit color values for the paletted modes. There are two areas of the palette: one for backgrounds (0x05000000) and another for sprites (0x05000200). Each of these is either indexed as a single, 256-color palette, or as 16 individual 16-color palettes, depending on the settings of a particular sprite or background.
93 |
94 |
95 | ### Video RAM (VRAM)
96 |
97 | - Start: 0x06000000
98 | - End: 0x06017FFF
99 | - Size: 96kb
100 | - Port Size: 16 bit
101 | - Mirrors: Bytes 0x06010000 - 0x06017FFF is mirrored from 0x06018000 - 0x0601FFFF.
102 | The entire region from 0x06000000 - 0x06020000 is in turn mirrored every
103 | 0x20000 bytes from 0x06000000 - 0x06FFFFFF.
104 |
105 | The video RAM is used to store the frame buffer in bitmapped modes, and the tile data and tile maps for tile-based "text" and rotate/scale modes.
106 |
107 |
108 | ### OBJ Attribute Memory (OAM)
109 |
110 | - Start: 0x07000000
111 | - End: 0x070003FF
112 | - Size: 1kb
113 | - Port Size: 32 bit
114 | - Mirrors: Every 0x400 bytes from 0x07000000 to 0x07FFFFFF
115 |
116 | This is the Object Attribute Memory, and is used to control the GBA's sprites.
117 |
118 |
119 | The following areas of memory are technically cart-dependent, but can generally be expected to behave as described.
120 |
121 |
122 | ### Game Pak, Image 0 (ROM)
123 |
124 | - Start: 0x08000000
125 | - Size: The size of the cartridge (0 - 32 megabytes)
126 | - Port Size: 16 bit
127 | - Wait State: 0
128 |
129 | The ROM in the game cartridge appears in this area. If a cartridge is present on startup, the instruction found at location 0x08000000 is loaded into the program counter and execution begins from there. Note that the transfers to and from ROM are all 16 bits wide.
130 |
131 |
132 | ### Game Pak, Image 1 (ROM)
133 |
134 | - Start: 0x0A000000
135 | - Size: The size of the cartridge (0 - 32 megabytes)
136 | - Port Size: 16 bit
137 | - Wait State: 1
138 |
139 | This is a mirror of the ROM above. Used to allow multiple speed ROMs in a single game pak.
140 |
141 |
142 | ### Game Pak, Image 2 (ROM)
143 |
144 | - Start: 0x0C000000
145 | - Size: The size of the cartridge (0 - 32 megabytes)
146 | - Port Size: 16 bit
147 | - Wait State: 2
148 |
149 | This is a mirror of the ROM above. Used to allow multiple speed ROMs in a single game pak.
150 |
151 |
152 | ### Game Pak RAM
153 |
154 | - Start: 0x0E000000 (also seem to appear at 0x0F000000)
155 | - Size: 0 - 64 kb
156 | - Port Size: 8 bit
157 |
158 | This is either SRAM or Flash ROM. Used primarily for saving game data. SRAM can be up to 64kb but is usually 32 kb. It has a battery backup so has the longest life (in terms of how many times it can be written to) of all backup methods. Flash ROM is usually 64 kb. Its lifespan is determined by the number of rewrites that can be done per sector (a 10,000 rewrite minimum is cited by some manufacturers).
159 |
160 |
161 | ### EEPROM
162 |
163 | This is another kind of cart memory, but operates differently from SRAM or Flash ROM. Unfortunately, I don't know the details of how it can be accessed by the programmer ([send us a PR](https://github.com/gbadev-org/gbadoc) if you have more information on it). It uses a serial connection to transmit data. The maximum size is 128 mb, but it can be any size, and is usually 4 kb or 64 kb. Like Flash ROM it has a limited life; some manufacturers cite a minimum of 100,000 rewrites per sector.
164 |
165 | There may be other regions of memory known as DEBUG ROM 1 and DEBUG ROM 2, though I really don't know whether these are a part of commercial carts or if they are mapped to some part of the internal ROM, or if they're even available on a standard GBA.
166 |
167 | Note that EWRAM, IWRAM, VRAM, OAM, Palette RAM are all initialized to zero by the BIOS (i.e. you can expect them to be zeroed at startup).
168 |
--------------------------------------------------------------------------------
/content/sprites.md:
--------------------------------------------------------------------------------
1 |
2 | # OAM (sprites)
3 |
4 |
9 |
10 | The GBA supports 128 simultaneous sprites. These can be up to 64x64 pixels in size. The OAM, which starts at `0x07000000`, has one entry for each of the 128 sprites. Intermixed with this data are the rotation/scaling attributes, of which there are 32 sets of 4 16 bit values.
11 |
12 | Each OAM entry is 8 bytes long and has the following format:
13 |
14 |
15 |
16 |
17 | ## Bytes 1 and 2 (Attribute 0)
18 |
19 | F E D C B A 9 8 7 6 5 4 3 2 1 0
21 | S S A M T T D R J J J J J J J J
23 |
24 |
`1` = sprite is virtually double sized; allowing sheared sprite pixels to overflow sprite the size (specified by bits 14 - 15 of [OAM attribute 1](#attr1)). A 16x16 sized sprite is treated internaly as a 32x32 sprite. This specification comes in evidence when rotating a sprite at 45°, since the H/V size of the sprite becomes SQRT(16² + 16²) = SQRT(512) =~ 22.62 pixels. This will cause the sprite to appear clipped if this bit is set to 0. (Thanks to Kay for the description)
31 | | A-B (T) | `00` = normal
`01` = semi-transparent
`10` = obj window
`11` = illegal code
Note that semi-transparent sprites appear as transparent even if [REG_BLDCNT](registers.md#REG_BLDCNT) has the sprites bit turned off. Also note that sprites cannot be blended against one another. For more details, see [REG_BLDCNT](registers.md#REG_BLDCNT).
32 | | C (M) | enables mosaic for this sprite.
33 | | D (A) | 256 color if on, 16 color if off
34 | | E-F (S) | Sprite shape. This determines the size of the sprite when combined with bits E-F of attr1. See below for more info.
35 |
36 |
37 |
38 | ## Bytes 3 and 4 (Attribute 1)
39 |
40 | F E D C B A 9 8 7 6 5 4 3 2 1 0
42 | S S V H X X X I I I I I I I I I (standard sprites)
44 | S S F F F F F I I I I I I I I I (rotation/scaling on)
45 | 0000: 8 x 8 1000: 8 x 16
0001: 16 x 16 1001: 8 x 32
0010: 32 x 32 1010: 16 x 32
0011: 64 x 64 1011: 32 x 64
0100: 16 x 8 1100: Not used
0101: 32 x 8 1101: Not used
0110: 32 x 16 1110: Not used
0111: 64 x 32 1111: Not used
F E D C B A 9 8 7 6 5 4 3 2 1 0 62 | L L L L P P T T T T T T T T T T63 |
Tile number. This value indexes selects the bitmap of the tile to be displayed by indexing into the tile data area. Each index refernces 32 bytes, so the memory address of a tile is roughly `0x06010000 + T*32`. (see [Sprite Tile Data](#sprite-tile-data) for details)
68 | | A-B (P) |Priority. This controls the priority of the sprite. Note that sprites take precedence over backgrounds of the same priority. See the [description of priority](registers.md#priority) under REG_BG0 - REG_BG3 for a more detailed explanation.
69 | | C-F (L) |Palette number. If you use 16 color [palettes](memory.md#palette-ram), this tells you which palette number to use.
70 | 71 | 72 | 73 | ## Bytes 7 and 8 (Attribute 3) 74 | 75 |F E D C B A 9 8 7 6 5 4 3 2 1 0 77 | S I I I I I I I F F F F F F F F78 |
109 | pa = x_scale * cos(angle) 110 | pb = y_scale * sin(angle) 111 | pc = x_scale * -sin(angle) 112 | pd = y_scale * cos(angle)113 | 114 | ## Sprite Tile Data 115 | 116 | The tile data area contains the actual bitmap for each tile. The sprites do not share tile data with the BG layers as on the Gameboy Color. The sprite tile data starts at `0x06010000`. All tiles are 8x8 pixels large. Sprites use the second [palette](memory.md#palette-ram) which begins at `0x05000200`. For 256 color sprites, there are 64 bytes per tile, one byte per pixel. This is an 8-bit value which is an index into the 256 color palette. For 16-color sprites, [attribute 2](#attr2) of the OAM data contains a 4 bit index into 16 16-color palettes, and sprites have 32 bytes per tile, with 4 bits per pixel. Note that the tile index references 32 bytes at a time, so in the case of 256 color sprite tiles, you will want to set your tile number to reference ever other index (i.e. 0, 2, 4, 6, etc.). 117 | 118 | Another thing to note is that in the bitmapped modes (3-5) the memory required to hold background data is larger than 0x10000 bytes, forcing the GBA to cut away from available sprite tile data. Thus in these modes you may only reference sprites tiles of indices 512 and up. 119 | 120 | When the sprite is larger than 8x8 pixels, multiple tiles are glued together to make the sprite's width horizontally, and then vertically. How this is done depends on whether character data is stored in 2D or 1D mode (determined by bit 6 of [DISPCNT](registers.md#REG_DISPCNT)). 121 | 122 | 123 | ### 1D Mapping 124 | 125 | In 1D mode, tiles are stored sequentially. If you were to set up a 32x32 16-color sprite, and set the tile number to 5, the sprite would be displayed as follows: 126 | 127 |
128 | --------------------- 129 | | 5 | 6 | 7 | 8 | 130 | | | | | | 131 | --------------------- 132 | | 9 | 10 | 11 | 12 | 133 | | | | | | 134 | --------------------- 135 | | 13 | 14 | 15 | 16 | 136 | | | | | | 137 | --------------------- 138 | | 17 | 18 | 19 | 20 | 139 | | | | | | 140 | --------------------- 141 |142 | 143 | ### 2D Mapping 144 | 145 | Tiles on each row of the sprite are stored 32 slots in. Using the same 32x32 sprite above, with a tile number of 5, the sprite would be displayed as: 146 | 147 |
148 | --------------------- 149 | | 5 | 6 | 7 | 8 | 150 | | | | | | 151 | --------------------- 152 | | 37 | 38 | 39 | 40 | 153 | | | | | | 154 | --------------------- 155 | | 69 | 70 | 71 | 72 | 156 | | | | | | 157 | --------------------- 158 | | 101| 102| 103| 104| 159 | | | | | | 160 | --------------------- 161 |162 | -------------------------------------------------------------------------------- /content/windowing.md: -------------------------------------------------------------------------------- 1 | 2 | # Windowing 3 | 4 | Windowing is a method of dividing the screen into subsections known as (surprise) windows. The windows serve as boundary areas to determine where various layers of the GBA will be shown and where they will be clipped. There are two primary windows, win0 and win1, which can be enabled in [REG_DISPCNT](registers.md#REG_DISPCNT). There is also the "obj" window, which can be thought of as another window which is defined by the visible regions of the objs on screen. Finally there is the "outside" or "out" window - the area of the screen not already occupied by any other winodw. 5 | 6 | The position and size of WIN0 and WIN1 are determined by [REG_WIN0H](registers.md#REG_WIN0H), [REG_WIN1H](registers.md#REG_WIN1H), [REG_WIN0V](registers.md#REG_WIN0V), and [REG_WIN1V](registers.md#REG_WIN1V) (I/O offsets 0x40, 0x42, 0x44, 0x46). 7 | 8 | Exactly which characters and backgrounds appear within or without win0, win1, and the obj window is determined by [REG_WININ](registers.md#REG_WIN_IN) and [REG_WINOUT](registers.md#REG_WIN_OUT) (0x48 and 0x4A). 9 | 10 | Here are some things to keep in mind when using windows: 11 | 12 | * WIN0 and WIN1 are drawn from the left and top boundary up to but not including the right and bottom boundaries. 13 | 14 | * Everything in WIN0 appears "above" WIN1 (i.e. it has higher priority), and everything in windows 0 & 1 appears above the WINOUT and obj windows. 15 | 16 | * If a bg or the obj's are turned off in dispcnt, they're off in all windows regardless of the settings in win_in and win_out. 17 | 18 | * If only one window is on, WINOUT affects everything outside of it. If both windows are on, WINOUT affects everything outside both of them. i.e. it affects _(!WIN0) && (!WIN1)_. 19 | 20 | * If a window is on, but the effective display bits are all clear, the backdrop is displayed. 21 | 22 | * If the window left coordinate is greater than the window right coordinate, the window will be drawn outside of this region (i.e. to the left and to the right) rather than in the area inbetween. 23 | 24 | * Likewise, if the window top coordinate is greater than the window bottom coordinate, the window will be drawn to the top and the bottom. 25 | 26 | * A completely inverted window is drawn in the area outside of the "+" shaped region defined by its boundaries. 27 | 28 | Windows can be used in console games for a variety of different effects. Though the window registers define a square region, differently shaped windows can be achieved by using [HDMA](registers.md#REG_DMA0CNT) or [hblank interrupts](interrupts.md) to change the parameters each scanline. Lantern lighting (when the hero has a lantern or flashlight that illuminates a certain region of a cave) and x-ray vision (use of the window to cut away layers that are in front) are two common effects created with windows. More are certainly possible. 29 | 30 | Thanks again to gbcft for most of these notes and for his extensive testing on the nature of windowing. 31 | -------------------------------------------------------------------------------- /theme/css/general.css: -------------------------------------------------------------------------------- 1 | /* Base styles and content styles */ 2 | 3 | @import '../fonts/interweb/inter.css'; 4 | @import 'variables.css'; 5 | 6 | :root { 7 | /* Browser default font-size is 16px, this way 1 rem = 10px */ 8 | font-size: 62.5%; 9 | } 10 | 11 | html { 12 | font-family: "Inter", sans-serif; 13 | color: var(--fg); 14 | background-color: var(--bg); 15 | text-size-adjust: none; 16 | } 17 | 18 | body { 19 | margin: 0; 20 | font-size: 1.6rem; 21 | overflow-x: hidden; 22 | } 23 | 24 | code { 25 | font-family: "Source Code Pro", Consolas, "Ubuntu Mono", Menlo, "DejaVu Sans Mono", monospace, monospace !important; 26 | font-size: 0.875em; /* please adjust the ace font size accordingly in editor.js */ 27 | } 28 | 29 | /* Don't change font size in headers. */ 30 | h1 code, h2 code, h3 code, h4 code, h5 code, h6 code { 31 | font-size: unset; 32 | } 33 | 34 | .left { float: left; } 35 | .right { float: right; } 36 | .boring { opacity: 0.6; } 37 | .hide-boring .boring { display: none; } 38 | .hidden { display: none !important; } 39 | 40 | h2, h3 { margin-top: 2.5em; } 41 | h4, h5 { margin-top: 2em; } 42 | 43 | .header + .header h3, 44 | .header + .header h4, 45 | .header + .header h5 { 46 | margin-top: 1em; 47 | } 48 | 49 | h1:target::before, 50 | h2:target::before, 51 | h3:target::before, 52 | h4:target::before, 53 | h5:target::before, 54 | h6:target::before { 55 | display: inline-block; 56 | content: "»"; 57 | margin-left: -30px; 58 | width: 30px; 59 | } 60 | 61 | /* This is broken on Safari as of version 14, but is fixed 62 | in Safari Technology Preview 117 which I think will be Safari 14.2. 63 | https://bugs.webkit.org/show_bug.cgi?id=218076 64 | */ 65 | :target { 66 | scroll-margin-top: calc(var(--menu-bar-height) + 0.5em); 67 | } 68 | 69 | .page { 70 | outline: 0; 71 | padding: 0 var(--page-padding); 72 | margin-top: calc(0px - var(--menu-bar-height)); /* Compensate for the #menu-bar-hover-placeholder */ 73 | } 74 | .page-wrapper { 75 | box-sizing: border-box; 76 | } 77 | .js:not(.sidebar-resizing) .page-wrapper { 78 | transition: margin-left 0.3s ease, transform 0.3s ease; /* Animation: slide away */ 79 | } 80 | 81 | .content { 82 | overflow-y: auto; 83 | padding: 0 15px; 84 | padding-bottom: 50px; 85 | } 86 | .content main { 87 | margin-left: auto; 88 | margin-right: auto; 89 | max-width: var(--content-max-width); 90 | } 91 | .content p { line-height: 1.45em; } 92 | .content ol { line-height: 1.45em; } 93 | .content ul { line-height: 1.45em; } 94 | .content a { text-decoration: none; } 95 | .content a:hover { text-decoration: underline; } 96 | .content img { max-width: 100%; } 97 | .content .header:link, 98 | .content .header:visited { 99 | color: var(--fg); 100 | } 101 | .content .header:link, 102 | .content .header:visited:hover { 103 | text-decoration: none; 104 | } 105 | 106 | table { 107 | margin: 0 auto; 108 | border-collapse: collapse; 109 | } 110 | table td { 111 | padding: 3px 20px; 112 | border: 1px var(--table-border-color) solid; 113 | } 114 | table thead { 115 | background: var(--table-header-bg); 116 | } 117 | table thead td { 118 | font-weight: 700; 119 | border: none; 120 | } 121 | table thead th { 122 | padding: 3px 20px; 123 | } 124 | table thead tr { 125 | border: 1px var(--table-header-bg) solid; 126 | } 127 | /* Alternate background colors for rows */ 128 | table tbody tr:nth-child(2n) { 129 | background: var(--table-alternate-bg); 130 | } 131 | 132 | 133 | blockquote { 134 | margin: 20px 0; 135 | padding: 0 20px; 136 | color: var(--fg); 137 | background-color: var(--quote-bg); 138 | border-top: .1em solid var(--quote-border); 139 | border-bottom: .1em solid var(--quote-border); 140 | } 141 | 142 | 143 | :not(.footnote-definition) + .footnote-definition, 144 | .footnote-definition + :not(.footnote-definition) { 145 | margin-top: 2em; 146 | } 147 | .footnote-definition { 148 | font-size: 0.9em; 149 | margin: 0.5em 0; 150 | } 151 | .footnote-definition p { 152 | display: inline; 153 | } 154 | 155 | .tooltiptext { 156 | position: absolute; 157 | visibility: hidden; 158 | color: #fff; 159 | background-color: #333; 160 | transform: translateX(-50%); /* Center by moving tooltip 50% of its width left */ 161 | left: -8px; /* Half of the width of the icon */ 162 | top: -35px; 163 | font-size: 0.8em; 164 | text-align: center; 165 | border-radius: 6px; 166 | padding: 5px 8px; 167 | margin: 5px; 168 | z-index: 1000; 169 | } 170 | .tooltipped .tooltiptext { 171 | visibility: visible; 172 | } 173 | 174 | .chapter li.part-title { 175 | color: var(--sidebar-fg); 176 | margin: 5px 0px; 177 | font-weight: bold; 178 | } 179 | -------------------------------------------------------------------------------- /theme/head.hbs: -------------------------------------------------------------------------------- 1 | 2 | 15 | 16 | --------------------------------------------------------------------------------