├── .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 | 117 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # gbadoc 2 | 3 | Community initiated GBA Technical documentation effort. 4 | 5 | We're currently in the early stages. Join the discussions on RFCs and first content in the [Issues](https://github.com/gbdev/gbadoc/issues/) and join the `#documentation` chat channel on the [gbadev](https://discord.io/gbadev) discord. 6 | 7 | ## Building the documentation 8 | 9 | The book is written in markdown and compiled to HTML using [mdbook][mdb-gh]. 10 | It's a tool written in Rust, but you do *not* have to have Rust installed to use it. 11 | There are [pre-built binaries][mdb-bins] available. 12 | 13 | [mdb-gh]: https://github.com/rust-lang/mdBook 14 | 15 | [mdb-bins]: https://github.com/rust-lang/mdBook/releases 16 | 17 | Basic usage: 18 | 19 | * `mdbook serve`: builds the book and serves it at `http://localhost:3000`. 20 | This will continue to watch the files while it's serving. 21 | Any changes on disk will automatically trigger a new build, 22 | and you'll see the changes just by refreshing your browser. 23 | * `mdbook serve --open`: as above, but this also opens a browser tab to the correct URL for you. 24 | -------------------------------------------------------------------------------- /book.toml: -------------------------------------------------------------------------------- 1 | [book] 2 | title = "gbadoc" 3 | author = "The Awesome GBA Dev Contributors" 4 | description = "Documents the workings of the Game Boy Advance hardware" 5 | src = "content" 6 | language = "en" 7 | 8 | [build] 9 | build-dir = "target/book" 10 | create-missing = true 11 | 12 | [output.html] 13 | mathjax-support = true 14 | -------------------------------------------------------------------------------- /content/SUMMARY.md: -------------------------------------------------------------------------------- 1 | # GBA Doc 2 | 3 | * [Intro](intro.md) 4 | * [System Overview]() 5 | * [Memory Layout](memory.md) 6 | * [Built-in Peripherals]() 7 | * [IO Register Summary](registers.md) 8 | * [Graphics](graphics.md) 9 | * [Backgrounds](backgrounds.md) 10 | * [OAM (Sprites)](sprites.md) 11 | * [Windowing](windowing.md) 12 | * [Mosaic]() 13 | * [Blending]() 14 | * [Stereoscopy]() 15 | * [Audio](audio/introduction.md) 16 | * [Direct Sound](audio/directsound.md) 17 | * [DMG Sound]() 18 | * [Sound Channel 1](audio/sound1.md) 19 | * [Sound Channel 2](audio/sound2.md) 20 | * [Sound Channel 3](audio/sound3.md) 21 | * [Sound Channel 4](audio/sound4.md) 22 | * [Sound Registers](audio/registers.md) 23 | * [DMA]() 24 | * [Timers]() 25 | * [External IO]() 26 | * [Keypad Buttons]() 27 | * [Serial Port]() 28 | * [Normal / SPI]() 29 | * [Multiplay]() 30 | * [JOYBUS]() 31 | * [UART]() 32 | * [GPIO]() 33 | * [Interrupt Controller]() 34 | * [System Control]() 35 | * [Cartridge Slot]() 36 | * [Power-Saving Features]() 37 | * [Test Mode]() 38 | * [Game Boy Color mode]() 39 | * [Programmers' Reference]() 40 | * [CPU](cpu.md) 41 | * [BIOS]() 42 | * [Built-in Functions (SWIs)](bios.md) 43 | * [System Functions]() 44 | * [Math Functions]() 45 | * [Memory Functions]() 46 | * [Decompression Functions]() 47 | * [Sound Functions]() 48 | * [MusicPlayer Functions]() 49 | * [Multiboot Function]() 50 | * [BIOS Memory]() 51 | * [Startup Sequence]() 52 | * [Multiboot]() 53 | * [MusicPlayer]() 54 | * [Interrupt Handling](interrupts.md) 55 | * [Cartridges]() 56 | * [Cartridge Header]() 57 | * [Save Types]() 58 | * [SRAM]() 59 | * [EEPROM]() 60 | * [Flash]() 61 | * [Cartridge Hardware]() 62 | * [GPIO Cartridge]() 63 | * [Cartridge RTC]() 64 | * [Cartridge Light Sensor]() 65 | * [Cartridge Rumble]() 66 | * [Cartridge Gyroscope]() 67 | * [Cartridge Accelerometer]() 68 | * [e-Reader]() 69 | * [Accessories]() 70 | * [Game Boy Player]() 71 | * [Wireless Adapter]() 72 | * [Hardware Specifications]() 73 | * [Pinouts]() 74 | * [Cartridge]() 75 | * [LCD]() 76 | * [EXT Ports]() 77 | * [SoC]() 78 | * [Signals and Buses]() 79 | * [Cartridge Protocol]() 80 | * [LCD Driving Waveforms]() 81 | * [EXRT Port Signals]() 82 | * [SIO SPI]() 83 | * [SIO Multiplay]() 84 | * [SIO JOYBUS]() 85 | * [SIO UART]() 86 | * [Guides]() 87 | * [Fixed-Point Math for Newbies](fixed-point-math.md) 88 | * [Bootleg Carts](bootleg-carts/introduction.md) 89 | * [Acknowledgements](ack.md) 90 | -------------------------------------------------------------------------------- /content/ack.md: -------------------------------------------------------------------------------- 1 | # Acknowledgements 2 | 3 | - [Velipso](https://github.com/velipso), author of the Bootleg Carts article. 4 | 5 | --- 6 | 7 | The following are individuals who contributed info or corrections on the original CowBiteSpec document. 8 | 9 | - Tom Happ 10 | - Agent Q (Wrote the original spec, version 1.0) 11 | - Uze (All of the sound register info comes directly from his Audio Advance site) 12 | - Martin Korth (Author no$gba of who has given me permission to consolidate additional info from his emulator's informative help documents with this one, most particularly serial registers, some BIOS functions, and undocumented registers.) 13 | - Forgotten (VBA Author. Many of the BIOS call descriptions come from his Visual Boy Advance FAQ. 14 | - gbcft (LOTS of info on interrupts, windowing, memory mirrors, the "Unkown Registers" section; helped me debug a lot of errors in the emulator, and offered many corrections, info, and suggestions). 15 | - Kay (Contributed memory port sizes and wait states, DMA cycle timings, info regarding the BIOS, and various advice, testing, and expertise regarding the GBA and older console systems) 16 | - Damian Yerrick (Contributed the WSCOUNT register) 17 | - Markus (Actually I asked him for help with LZSS. Also, his gfx2gba tool has proven extremely helpful in my non-CowBite projects.:) 18 | - ePac (Gave me links to serial info and did a nice writeup about it in the gbadev group) 19 | - Costis (A variety of new info/corrections) 20 | - Grauw (Info on forced blanking, hblank lenghths, and on the BIOS wait function.) 21 | - Max 22 | - Otaku 23 | - Ped (Pointed out errors in the memory ranges, DISPCNT bit 5, and a bad typo regarding rotates/scale backgrounds). 24 | - Yarpen (Almost all the information on the timer registers and the keyboard control register. Thanks!) 25 | - http://www.gbadev.org/ 26 | - The gbadev list on yahoo 27 | - SimonB and all the others who run/moderate the above sites 28 | - Dovoto and the PERN Project 29 | - Jeff Frohwein and his Devrs.com site 30 | - Nocturn and his tutorials 31 | - Uze from BeLogic for all the great information on the GBA's sound! 32 | - Andrew May for his site on GBA serial data 33 | 34 | Thank you to Alec Bourque for allowing us to use all assets of The Audio Advance in this documentation. -------------------------------------------------------------------------------- /content/audio/directsound.md: -------------------------------------------------------------------------------- 1 | # Direct Sound 2 | 3 | Direct Sound (not to confuse with DirectSound which is a registered trademark of Microsoft) refers to the two 8-bit digitial-to-analog converters part of the Gameboy Advance sound system (GBAS). The samples to be played, which must be 8-bit signed, are loaded in consecutive adresses starting at 0x040000A0 (REG_FIFO_A). These adresses acts as a FIFO (First-In-First-Out), meaning that lower adresses bytes are played first. Playback frequency is controlled by the overflow of either Timer 0 or Timer 1, allowing the two Direct sound channels to play at different frequencies independently. Direct sound can work in two modes: DMA mode and Interrupt mode. DMA mode is the most efficient way of playing Direct sound. Because once empty, sound FIFOs are automatically reloaded with the next samples by the DMA controller, without any program intervention. The other mode uses an interrupt handler that manually load the FIFOs. This is less efficient than DMA mode but in some cases, it is the only solution. 4 | 5 | ## Direct Sound Output Control Register 6 | 7 | | Offset | Name | 8 | | ------ | -------------- | 9 | | 0x082 | REG_SOUNDCNT_H | 10 | 11 | | Bit(s) | Effect | Access | 12 | | ------ | ----------------------------------------------------- | ------ | 13 | | 1-0 | Output sound ratio for chan. 1-4 (0=25%,1=50%,2=100%) | RW | 14 | | 2 | Direct sound A output ratio (0=50%, 1=100%) | RW | 15 | | 3 | Direct sound B output ratio (0=50%, 1=100%) | RW | 16 | | 7-4 | Unused | | 17 | | 8 | Direct sound A to right output | RW | 18 | | 9 | Direct sound A to left output | RW | 19 | | A | Direct sound A Sampling rate timer (timer 0 or 1) | RW | 20 | | B | Direct sound A FIFO reset | RW | 21 | | C | Direct sound B to right output | RW | 22 | | D | Direct sound B to left output | RW | 23 | | E | Direct sound B Sampling rate timer (timer 0 or 1) | RW | 24 | | F | Direct sound B FIFO reset | RW | 25 | 26 | Output ratios control the output volume. Set these bits when Sound 1-4 or Direct Sound plays too loud relative to each other. Direct Sound channels can be send to Left, Rigth or both outputs. Bit A and E selects which timer to use as the sampling frequncy reference. Both Direct sound channels can use the same timer, and it is usually the case for software mixing. FIFO reset prepares the Direct sound harware for playback and put the playing cursor back to FIFO's sample 0. It should always be performed before playback start. 27 | 28 | The following examples demonstrate Direct Sound playback in DMA mode and Interrupt mode. 29 | 30 | ## DMA Mode Direct Sound Example 31 | 32 | To use DirectSound in DMA mode: 33 | 34 | - Set DS outputs and volumes 35 | - Set timer0 (or 1) count value to 0xffff-round(cpuFreq/playbackFreq) 36 | - ie: For 16khz, timer count=65536-round(2^24/16000)=0xFBE8 37 | - Set DMA channel's source to the sample's address and destination adress to either FIFOA or FIFOB adresses 38 | - Reset the FIFO before starting sound by setting the FIFO reset bit. 39 | - Set DMA start mode to 11 to instruct DMA to repeat on FIFO-empty requests. Many documents list this state as invalid, which is naturally not the case. 40 | - ie:REG_DMA1CNT_H=0xb600=DMA enabled+ start on FIFO+32bit+repeat 41 | - Set DMA repeat and 32bit moves and set source and destination modes to increment. 42 | - Enable timer0 at Cpu frequency (clock divider=0) 43 | 44 | Sound should start immediately and will play past the sample if not stopped. You can use timer1 to count played samples and stop the sound. To do this, set timer 1 to cascade and enable irq for timer 1 and set its count to 0xffff-samples count. Your irq handler should stop the sound by disabling timer 0 and the dma channel(s). 45 | 46 | ```C 47 | #include "gba.h" 48 | 49 | //the sample. its a pcm wave file converted to an elf file with objcopyroda.exe (devrs.com/gba) 50 | extern const u32 _binary_lo1234_pcm_start[]; 51 | 52 | //the interrupt handler from crt0.s 53 | void InterruptProcess(void) __attribute__((section(".iwram"))); 54 | 55 | void InterruptProcess(void) { 56 | //sample finished!,stop Direct sound 57 | REG_TM0CNT_H = 0; //disable timer 0 58 | REG_DMA1CNT_H = 0; //stop DMA 59 | 60 | //clear the interrupt(s) 61 | REG_IF |= REG_IF; 62 | 63 | 64 | void AgbMain(void) { 65 | //play a mono sound at 16khz 66 | //uses timer 0 as sampling rate source 67 | //uses timer 1 to count the samples played in order to stop the sound 68 | 69 | //enable DS A&B + fifo reset + use timer0 + max volume to L and R 70 | REG_SOUNDCNT_H = 0x0b0F; 71 | //turn sound chip on 72 | REG_SOUNDCNT_X = 0x0080; 73 | 74 | //dma1 source 75 | REG_DMA1SAD = (unsigned long) _binary_lo1234_pcm_start; 76 | //write to FIFO A address 77 | REG_DMA1DAD = 0x040000a0; 78 | //dma control: DMA enabled+ start on FIFO+32bit+repeat+increment source&dest 79 | REG_DMA1CNT_H = 0xb600; 80 | 81 | //0xffff-the number of samples to play 82 | REG_TM1CNT_L = 0x7098; 83 | //enable timer1 + irq and cascade from timer 0 84 | REG_TM1CNT_H = 0xC4; 85 | 86 | //enable irq for timer 1 87 | REG_IE = 0x10; 88 | //master enable interrupts 89 | REG_IME = 1; 90 | 91 | //Formula for playback frequency is: 0xFFFF-round(cpuFreq/playbackFreq) 92 | 93 | //16khz playback freq 94 | REG_TM0CNT_L = 0xFBE8; 95 | //enable timer0 96 | REG_TM0CNT_H = 0x0080; 97 | 98 | } 99 | ``` 100 | 101 | True stereo output is a simple extension of the above code: 102 | 103 | - Set REG_SOUNDCNT_H to send DS A to right output and DS B to left output 104 | - Set DMA1 source to the right buffer, and destination to DS A FIFO 105 | - Set DMA2 source to the left buffer, and destination to DS B FIFO 106 | - Set timer 0 as sampling rate source for both DS A&B 107 | 108 | ## Interrupt Mode Direct Sound Example 109 | 110 | DMA mode Direct Sound has reportedly being causing problems in multi-players games. This is because during DMA tranfers, if interrupts occurs, they are only processed upon completion of that DMA. That means possible transmission losses due to bytes in the serial buffer being overwitten before beign read. On possible solution to this problem would be the use of Interrupt mode Direct sound playback. In this mode you set a timer (again 0 or 1), to the sampling frequency, set it to generate interrupts and load the FIFO(s) in the interrupt handler. Note that this methodology might impose problems if interrupts are blocking (ie. not allowing multiple interrupts at once), however if several interrupts at once are allowed inside the handler, this should resolve the issue. 111 | 112 | To use Direct sound in Interrupt mode: 113 | 114 | - Set DS ouputs and volume 115 | - Set timer 0 frequency to 0xffff 116 | - Enable timer 0, set it to generate IRQs and set the clock divider to 1024 (gives 16384 hz ) 117 | - In the interrupt handler: 118 | - Load FIFO(s) each 4 samples with 4 bytes 119 | - Increment the sample counter 120 | - Stop timer 0 when sample end has be reached 121 | 122 | ```C 123 | #include "gba.h" 124 | 125 | //the sample. its an pcm wave file converted to an elf file with objcopyroda.exe (devrs.com/gba) 126 | extern const u32 _binary_lo1234_pcm_start[]; 127 | //the interrupt handler from crt0.s 128 | void InterruptProcess(void) __attribute__((section(".iwram"))); 129 | 130 | int iNextSample = 0; 131 | int SampleSize = 36712; 132 | 133 | void InterruptProcess(void) { 134 | //load FIFO each 4 samples with 4 bytes 135 | if (!(iNextSample & 3)) REG_SGFIFOA = _binary_lo1234_pcm_start[iNextSample >> 2]; 136 | 137 | iNextSample++; 138 | 139 | if (iNextSample > SampleSize) { 140 | //sample finished! 141 | REG_TM0CNT_H = 0; //disable timer 0 142 | } 143 | //clear the interrupt(s) 144 | REG_IF |= REG_IF; 145 | } 146 | 147 | void AgbMain(void) { 148 | //play a sample at 16Khz using interrupt mode 149 | 150 | //DirectSound A + fifo reset + max volume to L and R 151 | REG_SOUNDCNT_H = 0x0B0F; 152 | 153 | //turn sound chip on 154 | REG_SOUNDCNT_X = 0x0080; 155 | 156 | //enable timer 0 irq 157 | REG_IE = 0x8; 158 | //enable interrupts 159 | REG_IME = 1; 160 | 161 | /*set playback frequency. note: using anything else thank clock multipliers to serve as sample frequencies tends to generate distortion in the output. It has probably to do with timing and FIFO reloading. More testing need to be done. */ 162 | 163 | REG_TM0CNT_L = 0xffff; 164 | //enable timer at CPU freq/1024 +irq =16384Khz sample rate 165 | REG_TM0CNT_H = 0x00C3; 166 | } 167 | ``` 168 | -------------------------------------------------------------------------------- /content/audio/images/chan3wavstop.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gbadev-org/gbadoc/13f4a26a2925bcc17f21d813188fab57eef2497a/content/audio/images/chan3wavstop.gif -------------------------------------------------------------------------------- /content/audio/images/demo3.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gbadev-org/gbadoc/13f4a26a2925bcc17f21d813188fab57eef2497a/content/audio/images/demo3.gif -------------------------------------------------------------------------------- /content/audio/images/demos1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gbadev-org/gbadoc/13f4a26a2925bcc17f21d813188fab57eef2497a/content/audio/images/demos1.gif -------------------------------------------------------------------------------- /content/audio/images/envelope.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gbadev-org/gbadoc/13f4a26a2925bcc17f21d813188fab57eef2497a/content/audio/images/envelope.gif -------------------------------------------------------------------------------- /content/audio/images/lfsr.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gbadev-org/gbadoc/13f4a26a2925bcc17f21d813188fab57eef2497a/content/audio/images/lfsr.gif -------------------------------------------------------------------------------- /content/audio/images/lfsroutput.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gbadev-org/gbadoc/13f4a26a2925bcc17f21d813188fab57eef2497a/content/audio/images/lfsroutput.gif -------------------------------------------------------------------------------- /content/audio/images/sound3reset.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gbadev-org/gbadoc/13f4a26a2925bcc17f21d813188fab57eef2497a/content/audio/images/sound3reset.gif -------------------------------------------------------------------------------- /content/audio/images/sweeps.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gbadev-org/gbadoc/13f4a26a2925bcc17f21d813188fab57eef2497a/content/audio/images/sweeps.gif -------------------------------------------------------------------------------- /content/audio/images/waveduty.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gbadev-org/gbadoc/13f4a26a2925bcc17f21d813188fab57eef2497a/content/audio/images/waveduty.gif -------------------------------------------------------------------------------- /content/audio/introduction.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | The Gameboy Advance (GBA) sound system may seem to many as black magic because of the availability of information on this specific part of the machine is near inexistent. Moreover, finding relevant or accurate specs for the older Gameboy was and is still problematic. The result is that many will take little or no advantages of sound in their projects. This site will attempt to fill this gap, by providing an _Unofficial_, comprehensive and (well, as much as possible in the circumstances) accurate specification of the GBA sound system (GBAS). It is assumed that the reader will have some knowledge of the other basic functionalities of the GBA and knows how to program in C. 4 | 5 | The GBAS is a big step forward its older brothers because it now includes two Pulse Width Modulators (PWM) that act as digital-to-analog converters. This adds to the 4 sound channels present on the previous Gameboys. One important improvement to the sound system is that channel 3 's wave ram is now banked, allowing for distortion-free dynamic wave ram reloading. 6 | 7 | The GBA BIOS also contains many sound-related functions, for converting MIDI notes and playing music. BIOS may be covered in the future. 8 | 9 | # The Registers 10 | 11 | Sound registers, as for all other registers in the GBA, are memory mapped and they span from 0x04000060 to 0x040000A6. 12 | 13 | | Adress | Name | Function | 14 | | ---------- | --------------- | ------------------------------------------------- | 15 | | 0x04000060 | REG_SOUND1CNT_L | Sound 1 Sweep control | 16 | | 0x04000062 | REG_SOUND1CNT_H | Sound 1 Length, wave duty and envelope control | 17 | | 0x04000064 | REG_SOUND1CNT_X | Sound 1 Frequency, reset and loop control | 18 | | 0x04000068 | REG_SOUND2CNT_L | Sound 2 Lenght, wave duty and envelope control | 19 | | 0x0400006C | REG_SOUND2CNT_H | Sound 2 Frequency, reset and loop control | 20 | | 0x04000070 | REG_SOUND3CNT_L | Sound 3 Enable and wave ram bank control | 21 | | 0x04000072 | REG_SOUND3CNT_H | Sound 3 Sound lenght and output level control | 22 | | 0x04000074 | REG_SOUND3CNT_X | Sound 3 Frequency, reset and loop control | 23 | | 0x04000078 | REG_SOUND4CNT_L | Sound 4 Length, output level and envelope control | 24 | | 0x0400007C | REG_SOUND4CNT_H | Sound 4 Noise parameters, reset and loop control | 25 | | 0x04000080 | REG_SOUNDCNT_L | Sound 1-4 Output level and Stereo control | 26 | | 0x04000082 | REG_SOUNDCNT_H | Direct Sound control and Sound 1-4 output ratio | 27 | | 0x04000084 | REG_SOUNDCNT_X | Master sound enable and Sound 1-4 play status | 28 | | 0x04000088 | REG_SOUNDBIAS | Sound bias and Amplitude resolution control | 29 | | 0x04000090 | REG_WAVE_RAM0_L | Sound 3 samples 0-3 | 30 | | 0x04000092 | REG_WAVE_RAM0_H | Sound 3 samples 4-7 | 31 | | 0x04000094 | REG_WAVE_RAM1_L | Sound 3 samples 8-11 | 32 | | 0x04000096 | REG_WAVE_RAM1_H | Sound 3 samples 12-15 | 33 | | 0x04000098 | REG_WAVE_RAM2_L | Sound 3 samples 16-19 | 34 | | 0x0400009A | REG_WAVE_RAM2_H | Sound 3 samples 20-23 | 35 | | 0x0400009C | REG_WAVE_RAM3_L | Sound 3 samples 23-27 | 36 | | 0x0400009E | REG_WAVE_RAM3_H | Sound 3 samples 28-31 | 37 | | 0x040000A0 | REG_FIFO_A_L | Direct Sound channel A samples 0-1 | 38 | | 0x040000A2 | REG_FIFO_A_H | Direct Sound channel A samples 2-3 | 39 | | 0x040000A4 | REG_FIFO_B_L | Direct Sound channel B samples 0-1 | 40 | | 0x040000A6 | REG_FIFO_B_H | Direct Sound channel B samples 2-3 | 41 | -------------------------------------------------------------------------------- /content/audio/registers.md: -------------------------------------------------------------------------------- 1 | # GBA Sound Registers 2 | 3 | | Adress | Name | Function | 4 | | ---------- | --------------- | ------------------------------------------------- | 5 | | 0x04000060 | REG_SOUND1CNT_L | Sound 1 Sweep control | 6 | | 0x04000062 | REG_SOUND1CNT_H | Sound 1 Length, wave duty and envelope control | 7 | | 0x04000064 | REG_SOUND1CNT_X | Sound 1 Frequency, reset and loop control | 8 | | 0x04000068 | REG_SOUND2CNT_L | Sound 2 Lenght, wave duty and envelope control | 9 | | 0x0400006C | REG_SOUND2CNT_H | Sound 2 Frequency, reset and loop control | 10 | | 0x04000070 | REG_SOUND3CNT_L | Sound 3 Enable and wave ram bank control | 11 | | 0x04000072 | REG_SOUND3CNT_H | Sound 3 Sound lenght and output level control | 12 | | 0x04000074 | REG_SOUND3CNT_X | Sound 3 Frequency, reset and loop control | 13 | | 0x04000078 | REG_SOUND4CNT_L | Sound 4 Length, output level and envelope control | 14 | | 0x0400007C | REG_SOUND4CNT_H | Sound 4 Noise parameters, reset and loop control | 15 | | 0x04000080 | REG_SOUNDCNT_L | Sound 1-4 Output level and Stereo control | 16 | | 0x04000082 | REG_SOUNDCNT_H | Direct Sound control and Sound 1-4 output ratio | 17 | | 0x04000084 | REG_SOUNDCNT_X | Master sound enable and Sound 1-4 play status | 18 | | 0x04000088 | REG_SOUNDBIAS | Sound bias and Amplitude resolution control | 19 | | 0x04000090 | REG_WAVE_RAM0_L | Sound 3 samples 0-3 | 20 | | 0x04000092 | REG_WAVE_RAM0_H | Sound 3 samples 4-7 | 21 | | 0x04000094 | REG_WAVE_RAM1_L | Sound 3 samples 8-11 | 22 | | 0x04000096 | REG_WAVE_RAM1_H | Sound 3 samples 12-15 | 23 | | 0x04000098 | REG_WAVE_RAM2_L | Sound 3 samples 16-19 | 24 | | 0x0400009A | REG_WAVE_RAM2_H | Sound 3 samples 20-23 | 25 | | 0x0400009C | REG_WAVE_RAM3_L | Sound 3 samples 23-27 | 26 | | 0x0400009E | REG_WAVE_RAM3_H | Sound 3 samples 28-31 | 27 | | 0x040000A0 | REG_FIFO_A_L | Direct Sound channel A samples 0-1 | 28 | | 0x040000A2 | REG_FIFO_A_H | Direct Sound channel A samples 2-3 | 29 | | 0x040000A4 | REG_FIFO_B_L | Direct Sound channel B samples 0-1 | 30 | | 0x040000A6 | REG_FIFO_B_H | Direct Sound channel B samples 2-3 | 31 | 32 | ## DMG Sound Output Control 33 | 34 | | Offset | Name | 35 | | ------ | -------------- | 36 | | 0x080 | REG_SOUNDCNT_L | 37 | 38 | | Bit(s) | Effect | Access | 39 | | ------ | --------------------------- | ------ | 40 | | 2-0 | DMG Left Volume | RW | 41 | | 3 | Vin to Left on/off (?) | | 42 | | 6-4 | DMG Right Volume | RW | 43 | | 7 | Vin to Right on/off (?) | | 44 | | 8 | DMG Sound 1 to left output | RW | 45 | | 9 | DMG Sound 2 to left output | RW | 46 | | A | DMG Sound 3 to left output | RW | 47 | | B | DMG Sound 4 to left output | RW | 48 | | C | DMG Sound 1 to right output | RW | 49 | | D | DMG Sound 2 to right output | RW | 50 | | E | DMG Sound 3 to right output | RW | 51 | | F | DMG Sound 4 to right output | RW | 52 | 53 | _Notes_ 54 | 55 | 1. This register controls only the DMG output amplifiers and have no effects on the individual sound channels processing, or Direct Sound channels volume. 56 | 2. Vin Left/Right were used on the original gameboy to enable gamepaks to provide their own sound source. It is currently unknown if this function is still supported and working on the GBA. 57 | 58 | ## Direct Sound Output Control Register 59 | 60 | | Offset | Name | 61 | | ------ | -------------- | 62 | | 0x082 | REG_SOUNDCNT_H | 63 | 64 | | Bit(s) | Effect | Access | 65 | | ------ | ----------------------------------------------------- | ------ | 66 | | 1-0 | Output sound ratio for chan. 1-4 (0=25%,1=50%,2=100%) | RW | 67 | | 2 | Direct sound A output ratio (0=50%, 1=100%) | RW | 68 | | 3 | Direct sound B output ratio (0=50%, 1=100%) | RW | 69 | | 7-4 | Unused | | 70 | | 8 | Direct sound A to right output | RW | 71 | | 9 | Direct sound A to left output | RW | 72 | | A | Direct sound A Sampling rate timer (timer 0 or 1) | RW | 73 | | B | Direct sound A FIFO reset | RW | 74 | | C | Direct sound B to right output | RW | 75 | | D | Direct sound B to left output | RW | 76 | | E | Direct sound B Sampling rate timer (timer 0 or 1) | RW | 77 | | F | Direct sound B FIFO reset | RW | 78 | 79 | _Notes_ 80 | 81 | 1. Output ratios control the output volume. Use when DMG channels or Direct Sound plays too loud relative to each other. 82 | 2. Direct Sound is a dual 8-bit DAC fed by data located in two FIFOs. FIFOs can be loaded manually or automatically in DMA mode when set appropriately. The DMA mode uses the timers specified in bits A and E as the sampling frequency reference. A single timer can be used for both DirectSound A&B. However, 2 DMA channels (1&2) must be used to output two different sounds simultaneously on both channels. Also, DMA channel start mode must be set to 11 to instruct it to repeat on FIFO-empty requests. 83 | 84 | ## Master Sound Output Control/Status 85 | 86 | | Offset | Name | 87 | | ------ | -------------- | 88 | | 0x084 | REG_SOUNDCNT_X | 89 | 90 | | Bit(s) | Effect | Access | 91 | | ------ | -------------------------------------- | ------ | 92 | | 0 | DMG Sound 1 status | R | 93 | | 1 | DMG Sound 2 status | R | 94 | | 2 | DMG Sound 3 status | R | 95 | | 3 | DMG Sound 4 status | R | 96 | | 6-4 | Unused | | 97 | | 7 | All sound circuit enable (0=off, 1=on) | RW | 98 | | F-8 | Unused | | 99 | 100 | _Notes_ 101 | 102 | 1. Bits 0-3 are set when their respective sound channels are playing and are resetted when sound has stopped. Note that contrary to some other sources and most emulators, these bits are read-only and do not need to be set to enable the sound channels. 103 | 2. Bit 7 turns on or off the entire sound circuit (DMG and Direct Sound). Keep this bit cleared as often as possible in order to save battery power. Some sources states that it allows batteries to last up to 10% longer. 104 | 105 | ## Sound Bias 106 | 107 | | Offset | Name | 108 | | ------ | ------------- | 109 | | 0x088 | REG_SOUNDBIAS | 110 | 111 | | Bit(s) | Effect | Access | 112 | | ------ | ---------------------------------------------------------------------------------------------------------------------------------------- | ------ | 113 | | 9-0 | DC offset bias value | RW | 114 | | D-A | Unused | | 115 | | F-E | PWM resampling resolution where:
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 | ![Sweeps example](images/sweeps.gif) 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 | ![Envelope example](images/envelope.gif) 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 | ![Wave duty example](images/waveduty.gif) 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 | ![Demo 1 example](images/demos1.gif) 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 68 | 69 | void AgbMain(void) { 70 | //Play a sound on channel 1 71 | 72 | //turn on sound circuit 73 | REG_SOUNDCNT_X = 0x80; 74 | //full volume, enable sound 1 to left and right 75 | REG_SOUNDCNT_L = 0x1177; 76 | // Overall output ratio - Full 77 | REG_SOUNDCNT_H = 2; 78 | 79 | //sweep shifts=6, increment, sweep time=39.1ms 80 | REG_SOUND1CNT_L = 0x0056; 81 | 82 | //duty=50%,envelope decrement 83 | REG_SOUND1CNT_H = 0xf780; 84 | //frequency=0x0400, loop mode 85 | REG_SOUND1CNT_X = 0x8400; 86 | 87 | } 88 | ``` 89 | -------------------------------------------------------------------------------- /content/audio/sound2.md: -------------------------------------------------------------------------------- 1 | # Sound Channel 2 2 | 3 | Sound channel 2 produces square waves with variable duty cycle and envelope functions. Channel 2 is identical to channel 1 but without the frequency sweep function. 4 | 5 | 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_SOUND2CNT_L. 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. 6 | 7 | Bit 11 of REG_SOUND2CNT_L controls the envelope direction: 0=envelope decreases and 1=envelope increases. 8 | 9 | The initial value of the envelope is stored in bits 12-15 of REG_SOUND2CNT_L. 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. 10 | 11 | ![Envelope example](images/envelope.gif) 12 | 13 | Envelope example for REG_SOUND2CNT_L=0x7400. 14 | 15 | Sound 2 can be set to either play for a specified duration or continuously. This is controlled by bit 14 of REG_SOUND2CNT_H. When set to 0 (continuous mode), sound is played continuously regardless of the length data in REG_SOUND2CNT_L. When set to 1 (timed mode), sound is played for that specified length and after that the DMG Sound 2 status bit of REG_SOUNDCNT_X is reset. 16 | 17 | The sound length (bits 0-5 of REG_SOUND2CNT_L) is a value obtained from the following formula: 18 | 19 | **Sound length = (64-register value)\*(1/256) seconds** 20 | 21 | When using timed mode, after the sound length has be changed, the sound channel must be resetted via bit 15 of REG_SOUND2CNT_H. 22 | 23 | Frequency (bits 0-10 of REG_SOUND2CNT_H) can be calculated from the following formula: 24 | 25 | **F(Hz) = 4194304/(32\*(2048-register value)). The minimum frequency is 64Hz and the maximum is 131Khz.** 26 | 27 | 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_SOUND2CNT_L. 28 | 29 | Possible duty cycles: 30 | 31 | ![Wave duty example](images/waveduty.gif) 32 | 33 | 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). 34 | 35 | ## Sound Channel 2 Demo 36 | 37 | ![Demo 1 example](images/demos1.gif) 38 | 39 | ```C 40 | #include 41 | 42 | void AgbMain(void) { 43 | //Play a sound on channel 2 44 | 45 | //turn on sound circuit 46 | REG_SOUNDCNT_X = 0x80; 47 | //full volume, enable sound 2 to left and right 48 | REG_SOUNDCNT_L = 0x2277; 49 | // Overall output ratio - Full 50 | REG_SOUNDCNT_H = 2; 51 | 52 | //duty=50%,envelope decrement 53 | REG_SOUND2CNT_L = 0xf780; 54 | //frequency=0x0400, loop mode 55 | REG_SOUND2CNT_H = 0x8400; 56 | 57 | } 58 | ``` 59 | -------------------------------------------------------------------------------- /content/audio/sound3.md: -------------------------------------------------------------------------------- 1 | # Sound Channel 3 2 | 3 | Channel 3 acts as a 4-bit DAC that repeatadely plays a pattern of samples. This pattern is user definable and consists of sixty-four 4-bit samples, separated in two banks and located from 0x04000090 to 0x0400009F. Channel 3 can play banks in two modes: As a single 64 samples bank or two 32 samples banks. The dual bank mode has the advantage of not needing a sound reset/restart when switching the playing bank. This allows for dynamic reloading of the wave ram without generating distortion as it was the case with previous Gameboys. Bank mode is controlled by bit 5 of REG_SOUND3CNT_L (0x04000070) and resetting it to 0 specifies dual bank mode. 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. 4 | 5 | When bit 7 is set and Initial flag (Bit 15) from REG_SOUND3CNT_X is set, the wave pattern starts to play. Both banks of Wave Ram are filled with zero upon initialization of the Gameboy, Bank 0 being selected. So writing to bank 0 implie setting bit 6 to 1 before loading Wave Ram then set it back to 0 to play it. Most emulator currently ignore banks. 6 | 7 | Sound 3 can be set to either play for a specified duration (max 1 second) or continuously. This is controlled by bit E of REG_SOUND3CNT_H (0x04000074). When 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. 8 | 9 | The sound length is a 8 bit value obtained from the following formula: 10 | 11 | **Register = Note lenght(in seconds)\*256, hence a 1 second maximum And a 3.9 millisecond minimum sound duration.** 12 | 13 | After the sound length has be changed, the sound channel must be resetted via bit F of REG_SOUND3CNT_H. 14 | 15 | Frequency can be calculated from the following formula: 16 | 17 | **F(hz) = 4194304/(32\*(2048-register value)). The minimum frequency is 64Hz and the maximum is 131Khz.** 18 | 19 | When the sound is reset, it restarts at the specified frequency. Frequency setting and sound reset must be performed in a single write since both are write only. Note that in continuous mode, frequency can be changed without resetting the sound channel (the reset bit is ignored). 20 | 21 | ## Sound Channel 3 Demo 22 | 23 | ![Demo 3 example](images/demo3.gif) 24 | 25 | A comprehensive demo is included. It shows most features of channel 3. The demo also explores two ways of stopping the sound while its playing. The counter mode, where sound stops after the time specified in the sound lenght register, and interrupt mode, where an timer interrupt stop the sound after a period of time. The problem with counter mode is that the sound channel must be resetted before restarting another note. This causes very annoying audio artefacts as demonstrated in the following picture: 26 | 27 | ![Sound 3 Reset example](images/sound3reset.gif) 28 | 29 | We can cleary see spikes at the end and start of the sound. In the demo select voice 1 and press start to swap between stop modes. When in counter mode, the clicks are clearly evident. 30 | 31 | We can set a timer interrupt to stop sound after a period of time. In the handler, we stop sound by clearing channel 3's play bit or setting its volume to zero. But both approaches tends to distort the sound, though less severely than counter mode. Here's the effect: 32 | 33 | ![Chan 3 Wav Stop example](images/chan3wavstop.gif) 34 | 35 | Using the main sound output control register REG_SOUNDCNT_L, and clear the left/right output bits gives the best results. 36 | 37 | ```C 38 | #include 39 | 40 | void AgbMain(void) { 41 | //Play a continuous tone using channel 3 42 | 43 | //turn on sound circuit 44 | REG_SOUNDCNT_X = 0x80; 45 | //full volume, enable sound 3 to left and right 46 | REG_SOUNDCNT_L = 0x4477; 47 | // Overall output ratio - Full 48 | REG_SOUNDCNT_H = SOUND3OUTPUT1; 49 | 50 | //select bank 0 for writing (bank 1 playing) 51 | REG_SOUND3CNT_L = SOUND3BANK32 | SOUND3SETBANK1; 52 | //load the wave ram bank 0 53 | REG_WAVE_RAM0 = 0x10325476; 54 | REG_WAVE_RAM1 = 0x98badcfe; 55 | REG_WAVE_RAM2 = 0x10325476; 56 | REG_WAVE_RAM3 = 0x98badcfe; 57 | //select bank 0 for playing 58 | REG_SOUND3CNT_L = SOUND3BANK32 | SOUND3SETBANK0; 59 | 60 | REG_SOUND3CNT_L |= SOUND3PLAY; 61 | REG_SOUND3CNT_H = SOUND3OUTPUT1; 62 | //play a C-4 in loop mode 63 | REG_SOUND3CNT_X = SOUND3INIT | SOUND3PLAYLOOP | 1046; 64 | } 65 | ``` 66 | -------------------------------------------------------------------------------- /content/audio/sound4.md: -------------------------------------------------------------------------------- 1 | # Sound Channel 4 2 | 3 | Sound channel 4 produces Pseudo-Noise with an envelope function. Noise is generated by a polynomial counter also known as a Linear-Feedback Shift Register (LFSR). LFSRs are special type of binary counter that have the particularity of not counting in the normal binary increment/decrement sequence. These counters find common uses in pseudorandom-numbers generation. Theory behind LFSRs and Polynomial counters are out of the scope of this document but a simple approach to key concepts will be described. Good references on the subjects are given at the end of this document. 4 | 5 | The pseudo-noise pattern playback frequency can be controlled by a 3-bit clock divider used to divide the Sound system's clock (4.194304Mhz). The clock divider's output is then fed into a pre-scaler which output is then used as the polynomial counter's clock. The counter can be set to user either 7 or 15 stages/steps. Resulting into a 127 or 32767 input clock cycle period. Using 7 stages give more metallic sounding effects when played faster (lower divider ratios) while 15 stages sounds much like white noise. 6 | 7 | Selection of the clock divider is done by bits 0-2 of REG_SOUND4CNT_H, where f=4.194304 Mhz/8: 8 | 9 | - 000: f\*2 10 | - 001: f 11 | - 010: f/2 12 | - 011: f/3 13 | - 100: f/4 14 | - 101: f/5 15 | - 110: f/6 16 | - 111: f/7 17 | 18 | Bit 3 of REG_SOUND4CNT_H control the number of counter stages: 0=15 stages, 1=7 stages. 19 | 20 | Selection of the pre-scaler divider value is done by bits 4-7 of REG_SOUND4CNT_H, where Q is the clock divider's output: 21 | 22 | - 0000: Q/2 23 | - 0001: Q/2^2 24 | - 0010: Q/2^3 25 | - 0011: Q/2^4 26 | - .... 27 | - 1101: Q/2^14 28 | - 1110: Not used 29 | - 1111: Not used 30 | 31 | The REG_SOUND4CNT_L contains the envelope function and the sound's length and its functionality is identical to channel 1. 32 | 33 | Bit 14 of REG_SOUND4CNT_H control the loop/timed mode. If set to 1 sound plays for the duration specified in REG_SOUND4CNT_L otherwise sound plays continuously. Bit 15 resets the sound and the LSFR counter. 34 | 35 | All registers can be modified during playback but sound need to be reinitialized when modifying the envelope initial volume or the clock divider for changes to take effects. 36 | 37 | ## How it works 38 | 39 | This section is more intended to emulator writers who wants to implement the exact sound of the original Gameboy sound system. 40 | 41 | An LFSR counter with n stages can implement a maximum of (2^n)-1 states, n representing the degree of the polynomial. All zeros state is not allowed because it locks the counters. Each state in the entire count sequence is generated once and only once. 42 | 43 | The Gameboy sound circuit implements a switchable 7/15-stages LFSR. Below is an representation of the logic used by the Gameboy. It is important to realize that channel 4 does not generate white noise per-se but Pseudo-noise. White noise is a special type of signal containing an equal amount of all frequencies and has no cycle period. LFSR counters have a cycle period of (2^n)-1 input clock cycles. Played at high speed, the pattern starts to exhibit a fundamental derived from the input clock frequency. This is clearly evident when using the 7-stages mode since the cycle is only 127 input clocks. 15-stages mode has a much bigger cycle, 32767, so the pseudo-noise sounds much more like white noise. 44 | 45 | ![LSFR example](images/lfsr.gif) 46 | 47 | When initialized, all shift registers are set to 1. On each clock pulse, bits are shifted from left to right (on the picture) s1 being the least significant bit and the output that is sent to the channel's envelope generator. The count sequence for the 7-stage LFSR, once the sound channel is resetted is then: 48 | 49 | **Counter steps** 50 | 51 | | | | | | | | | 52 | | --- | --- | --- | --- | --- | --- | --- | 53 | | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 54 | | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 55 | | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 56 | | 0 | 0 | 0 | 1 | 1 | 1 | 1 | 57 | | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 58 | | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 59 | | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 60 | | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 61 | | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 62 | | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 63 | | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 64 | | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 65 | | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 66 | | 1 | 0 | 0 | 0 | 0 | 0 | 1 | 67 | | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 68 | | 0 | 1 | 1 | 0 | 0 | 0 | 0 | 69 | | 0 | 0 | 1 | 1 | 0 | 0 | 0 | 70 | | 0 | 0 | 0 | 1 | 1 | 0 | 0 | 71 | | 0 | 0 | 0 | 0 | 1 | 1 | 0 | 72 | | 1 | 0 | 0 | 0 | 0 | 1 | 1 | 73 | | 0 | 1 | 0 | 0 | 0 | 0 | 1 | 74 | | 1 | 0 | 1 | 0 | 0 | 0 | 0 | 75 | | 0 | 1 | 0 | 1 | 0 | 0 | 0 | 76 | | 0 | 0 | 1 | 0 | 1 | 0 | 0 | 77 | | 0 | 0 | 0 | 1 | 0 | 1 | 0 | 78 | | 1 | 0 | 0 | 0 | 1 | 0 | 1 | 79 | | 1 | 1 | 0 | 0 | 0 | 1 | 0 | 80 | | 1 | 1 | 1 | 0 | 0 | 0 | 1 | 81 | | 1 | 1 | 1 | 1 | 0 | 0 | 0 | 82 | 83 | ![LFSR output example](images/lfsroutput.gif) 84 | 85 | By looking at s1 output (the the least significant bit), we can see it matches the pattern on the picture, which is a capture of the GBA output for channel 4 in 7-stage mode. Since the counter is always counting in the same sequence, the output bits can be stored in a lookup table for fast emulation of this function. By packing the bits, a 4 KB lookup table is sufficient to represent all states for both the 7 and 15 stages of the LFSR. 86 | 87 | ### References 88 | 89 | [n-Stage LFSR simulator Java applet](http://www.eecircle.com/applets/009/LFSR.html) 90 | 91 | [EDN article on LFSR](http://archives.e-insite.net/archives/ednmag/reg/1996/010496/01df4.htm) 92 | 93 | [Theory behind LFSR](http://www-math.cudenver.edu/~wcherowi/courses/m5410/m5410fsr.html) 94 | 95 | ```C 96 | #include 97 | 98 | void AgbMain(void) { 99 | //Play a sound on channel 4 100 | 101 | //turn on sound circuit 102 | REG_SOUNDCNT_X = 0x80; 103 | //full volume, enable sound 4 to left and right 104 | REG_SOUNDCNT_L = 0x4477; 105 | // Overall output ratio - Full 106 | REG_SOUNDCNT_H = 2; 107 | 108 | 109 | //envellope decay, initial vol max 110 | REG_SOUND4CNT_L = 0xf700; 111 | //Loop mode, clk div:6, 7-stage,pre-scaler:3 112 | REG_SOUND4CNT_H = 0x8032; 113 | 114 | } 115 | ``` 116 | -------------------------------------------------------------------------------- /content/backgrounds.md: -------------------------------------------------------------------------------- 1 | 2 | # Backgrounds 3 | 4 | 9 | 10 | Depending on the current [video mode](graphics.md#video-modes), three different types of backgrounds are available. They are: 11 | 12 | ### Text Backgrounds 13 | 14 | These are tile-based backgrounds that descend from the usage of tiles to display characters in text modes of a PC or workstation. They are made up of 8x8 tiles, the bitmaps of which are stored at the tile data address. The address of this data is set using registers [REG_BG0CNT - REG_BG3CNT](registers.md#REG_BGCNT). The [HOFS / VOFS](registers.md#REG_BGOFS) registers can be used to scroll around a larger area of up to 512x512 pixels (or 64 x 64 tiles). 15 | 16 | In text backgrounds, the data for each pixel is stored as an 8 or 4 bit palette index. In 8-bit mode, the [palette](memory.md#palette-ram) is at `0x05000000` stores a 15-bit color value for each of the 256 palette entries. In 4-bit mode, the the map index contains a 4-bit value indicating which of 16 16-color palettes to use for each tile. Each of these palettes is 32 bytes long and can be found at `0x05000000`, `0x05000020`, etc. 17 | 18 | ### Scale/Rotate Backgrounds 19 | 20 | These backgrounds are also tile-based, and operate similarly to Text Backgrounds. However, these backgrounds may also be [scaled or rotated](registers.md#background-rotation-scaling-registers). Additionally they may only use an 8-bit palette, and can vary in size from 128 to 1024 pixels across. The palette is at `0x05000000`, and contains 256 16-bit [color entries](graphics.md#color-format) 21 | 22 | ### Bitmapped Backgrounds 23 | 24 | These backgrounds vary depending on the [video mode](graphics.md#video-modes), but in all cases they rely on a single buffer upon which the image is drawn, either using an 8-bit palette or 16-bit color entries themsevles. Bitmap backgrounds are treated as BG2 for purposes of rotation, scaling, and blending. In the bitmap modes the frame buffer data extends into the obj tile data region, limiting it to the range from `0x06014000` - `0x06018000` (sprite indices 512 - 1024). 25 | 26 | ## Background Map Entry Format 27 | 28 | ### Text Background Map Format 29 | 30 | The tile map, which stores the layout of the tiles on screen, begins at the tile map address found for a particular background, detrmined by [REG_BG0CNT - REG_BG3CNT](registers.md#REG_BG0). It has a selectable size up to 512x512. The tile map contains a 16-bit entry for each tile, with has the following format: 31 | 32 |
33 |
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 |
36 | 37 | | Bits | Description | 38 | |---------|---------------------------------------------------------| 39 | | 0-9 (T) | The tile number 40 | | A (H) | If this bit is set, the tile is flipped horizontally left to right. 41 | | B (V) | If this bit is set, the tile is flipped vertically upside down. 42 | | C-F (L) | Palette number 43 | 44 | For 256 x 256 and 256 x 512 backgrounds, the formula for calculating a map index is roughly, 45 | 46 | mapEntry = tileMapAddress[(tileY * 32) + tileX] 47 | 48 | For text mode sizes 512 x 256 and 512 x 512 backgrounds, however, the map is 64 tiles across, and these are stored in blocks of 32 * 32 tiles. This means that to calculate the map entry that would appear 33 tiles or more across the background, the following equation should be used: 49 | 50 | mapEntry = tileMap[(tileY * 32) + (tileX - 32) + 32*32] 51 | 52 | For entries 33 tiles or more down (in mode 11), use 53 | 54 | mapEntry = tileMap[((tileY-32) * 32) + tileX + 2*32*32] 55 | 56 | And for entries 33 tiles or more down and 33 tiles or more across, 57 | 58 | mapEntry = tileMap[((tileY-32) * 32) + (tileX-32) + 3*32*32] 59 | 60 | 61 | ### Rotational Background Map Format 62 | 63 | This is the same idea as the text background map format, but you only have 8 bits for each entry. The format for the tile map entries is: 64 | 65 | 66 |
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 | ![Label Removal - Before and After](images/label.jpg) 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 | ![Back of Cart](images/back.jpg) 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 | ![Label Removal](images/label-removal.jpg) 58 | 59 | ## Flashing Cart 60 | 61 | ![Flashing Hardware](images/flashers.jpg) 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 | ![Cart Chips](images/chips.jpg) 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 | ![S29GL128N Commands](images/commands.png) 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 | ![Region Layout Memory Locations](images/regions.png) 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 4 | tt { 5 | white-space: pre; 6 | } 7 | 8 | 9 | This section is intended to be an overview only, detailing those aspects of the CPU which are important to understand when developing for the GBA in particular. A more thorough description of the ARM7tdmi CPU can be found in the [technical reference manuals](http://www.arm.com/arm/TRMs?OpenDocument) on [ARM's website](http://www.arm.com). 10 | 11 | The CPU is a 16.78 MHz ARM7tdmi RISC processor. It is a 32-bit processor but can be switched to "Thumb" state, which allows it to handle a special subset of 16-bit instructions that map to 32-bit counterparts. Instructions follow a three-stage pipeline: fetch, decode, execute. As a result, the [program counter](#r15 (PC)) always points two instructions ahead of the one currently being executed. 12 | 13 | ## CPU Registers 14 | 15 | 16 registers are visible to the user at any given time, though there are 20 [banked registers](#banked-registers) which get swapped in whenever the CPU changes to various priveleged modes. The registers visible in user mode are as follows: 16 | 17 | * **r0-r12:** General purpose registers, for use in every day operations 18 | 19 | * **r13 (SP):** Stack pointer Register. Used primarily for maintaining the address of the stack. This default value (initialized by the BIOS) differs depending on the current [processor mode](#processor-modes), as follows: 20 | 21 |
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 |
36 |
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 |
41 | 42 | | Bits | Description | 43 | |---------|---------------------------------------------------------| 44 | | 0-4 (M) |

Mode bits. These indicate the current processor mode:

`10000` - User mode
`10001` - FIQ mode
`10010` - IRQ mode
`10011` - Supervisor mode
`10111` - Abort mode
`11011` - Undefined mode
`11111` - System mode

45 | | 5 (T) | [Thumb state](#cpu-state) indicator. If set, the CPU is in Thumb state. Otherwise it operates in normal ARM state. Software should never attempt to modify this bit itself. 46 | | 6 (F) | FIQ interrupt disable. Set this to disable FIQ interrupts. 47 | | 7 (I) | [IRQ interrupt](interrupts.md) disable. Set this to disable IRQ interrupts. On the GBA this is set by default whenever IRQ mode is entered. Why or how this is the case, I do not know. 48 | | 8-27 (R) | Reserved 49 | | 28 (V) | Overflow condition code 50 | | 29 (C) | Carry/Borrow/Extend condition code 51 | | 30 (Z) | Zero/Equal condition code 52 | | 31 (N) | Negative/Less than condition code 53 | 54 | 55 | ## Processor Modes 56 | 57 | The ARM7tdmi has six modes: user, system, IRQ, FIQ, SVC, Undef, and Abt. The default is user mode. Certain events will trigger a mode switch. Some modes cause an alternate set of registers to be swapped in, effectively replacing the current set of registers until the mode is exited. 58 | 59 | * **User:** This is the default mode. 60 | 61 | * **System:** This is intended to be a priveleged user mode for the operating system. As far as I can tell it is otherwise the same as User mode. I am not sure if the GBA ever enters System mode during [BIOS](bios.md)) calls. 62 | 63 | * **IRQ:** This mode is entered when an Interrupt Request is triggered. Any interrupt handler on the GBA will be called in IRQ mode. 64 | 65 | * Banked registers: The ARM7tdmi has several sets of banked registers that get swapped in place of normal user mode registers when a priveleged mode is entered, to be swapped back out again once the mode is exited. In IRQ mode, r13\_irq and r14\_irq will be swapped in to replace r13 and r14. The current [CPSR](#CPSR) contents gets saved in the SPSR\_irq register. 66 | 67 | * **FIQ:** This mode is entered when a Fast Interrupt Request is triggered. Since all of the hardware interrupts on the GBA generate IRQs, this mode goes unused by default, though it would be possible to switch to this mode manually using the "msr" instruction. 68 | 69 | * Banked registers: r8\_fiq, r9\_fiq, r10\_fiq, r11\_fiq, r12\_fiq, r13\_fiq, r14\_fiq, and SPSR\_fiq. 70 | 71 | * **SVC:** Supervisor mode. Entered when a SWI (software interrupt) call is executed. The GBA enters this state when calling the [BIOS](bios.md) via SWI instructions. 72 | 73 | * Banked registers: r13\_svc, r14\_svc, SPSR\_svc. 74 | 75 | * **ABT:** Abort mode. Entered after data or instruction prefetch abort. 76 | 77 | * Banked registers: r13\_abt, r14\_abt, SPSR\_abt. 78 | 79 | * **UND:** Undefined mode. Entered when an undefined instruction is executed. 80 | 81 | * Banked registers: r13\_und, r14\_und, SPSR\_und. 82 | 83 | ### CPU State 84 | 85 | The ARM7tdmi has two possible states, either of which may be entered without fear of losing register contents or current processor mode. 86 | 87 | **To enter Thumb State**: In this state the CPU executes 16-bit, halfword-aligned instructions. There are two ways it can be entered: 88 | 89 | * A BX rn, where rn contains the address of the thumb instructions to be executed, +1. Bit 0 must be 1 or the switch won't be made and the CPU will try to interperet the binary Thumb code as 32-bit ARM instructions. 90 | * Returning from an [interrupt](interrupts.md) that was entered while in Thumb mode. 91 | * Executing any arithmetic instruction with the PC as the target and the 'S' bit of the instruction set, with bit 0 of the new PC being 1. 92 | 93 | **To Enter ARM State:** This is the default state. It executes 32-bit, word-aligned instructions. When in Thumb state, the CPU can be switched back to ARM state by: 94 | 95 | * A BX rn, where rn contains the address of the ARM instructions to be executed. Bit 0 must be 0. 96 | * Entering an [interrupt](interrupts.md). 97 | 98 | **For more complete information on the ARM7tdmi, be sure to check out ARM's [technical reference manuals](http://www.arm.com/arm/TRMs?OpenDocument).** 99 | -------------------------------------------------------------------------------- /content/fixed-point-math.md: -------------------------------------------------------------------------------- 1 | # Fixed-Point Math for Newbies 2 | 3 | You may have come across the term "fixed-point math" before, especially if you're into homebrew. What is fixed-point math, why do we use it, and how does it work? 4 | 5 | Fixed-point math is a common workaround for when a piece of hardware doesn't have a floating point unit, or FPU. A floating point unit, in simple terms, is what allows computers to deal with fractional values (such as 1.5) and very large values (such as one quintillion). The data types for these would be "floats" or "doubles". The first major console that was released with an FPU was the Nintendo 64 in 1996, but many consoles that were released after still didn't have one. 6 | 7 | The Game Boy Advance was one such device that didn’t have an FPU. If you try to use floats within your code, it will still compile and run, but it will have a major effect on the performance. This is because without an FPU, floats are emulated on the software level, instead of being handled directly by hardware. The code with floats will compile into something much longer. 8 | 9 | I'm going to focus on fractional values in this guide, but most of the same principles will apply for very large numbers as well. 10 | 11 | Before explaining how fixed-point math actually works, we need some background: 12 | 13 | ## What’s Binary, and How Do I Count in It? 14 | 15 | We humans use a base-10 system of counting, known as "decimal", where digits 0 to 9 are used to construct numbers. Computers use a base-2 system of counting, known as "binary". Binary only uses digits 0 and 1 to construct numbers. 16 | 17 | So, how do you count in binary? First, you count up to 1, then you carry over to the next digit, going left. That looks like this: 18 | 19 | ```c 20 | 00000000 // 0 21 | 00000001 // 1 22 | 00000010 // 2 23 | 00000011 // 3 24 | 00000100 // 4 25 | 00000101 // 5 26 | 00000110 // 6 27 | 00000111 // 7 28 | 00001000 // 8 29 | 00001001 // 9 30 | 00001010 // 10 31 | 00001011 // 11 32 | ``` 33 | 34 | And so on. Try continuing that series yourself, up to 16. 35 | 36 | Similar to our human decimal system (at least in English), the rightmost digit is the least significant (only corresponding to 1 or 0), and each digit going left is bigger; in decimal they would correspond to 2 or 0, 4 or 0, 8 or 0, etc. Note that each digit corresponds to an increasing power of 2 (1, 2, 4, 8, 16, 32, 64, 128). 37 | 38 | Each digit in binary is referred to as a 'bit'. In the previous example, it's 8 bits of information. This means that it can store 256 (2 to the power of 8) different values before running out of space. 39 | 40 | On the GBA, 8 bits is also known as a 'byte'. This is true for most hardware. The byte that is `00001011` is equal to "1 plus 2 plus 8", or 11, because the 1 and 2 and 8 bits are set. 41 | 42 | ## Bit Shifting 43 | 44 | So, let's say we have this number: 45 | 46 | ```c 47 | 00000110 // 6 48 | ``` 49 | 50 | We can "shift" these bits. That means taking the 1's and moving them left or right. The operators for this are usually `<<` for shifting left, and `>>` for shifting right. Just remember where the arrows point, and that will tell you the direction. Left makes it larger, and right makes it smaller. 51 | 52 | If we shift left by 1 bit, we get: 53 | 54 | ```c 55 | 00000110 // 6, before 56 | 00001100 // 12, after 57 | ``` 58 | 59 | All of the 1's shifted "to the left". Note that this is twice as big; we just multiplied by two. Now let's move 6 right by 1 bit. 60 | 61 | ```c 62 | 00000110 // 6, before 63 | 00000011 // 3, after 64 | ``` 65 | 66 | Woah! We shifted it "to the right" and it's half as big; we just divided by two. What if we shift 6 right by 2 bits instead of just 1? 67 | 68 | ```c 69 | 00000110 // 6, before 70 | 00000001 // 1, after 71 | ``` 72 | 73 | It looks like we clipped the rightmost digit in this process. 6 divided by 4 is 1.5, but we don't have space for anything to the right of the decimal point, so the .5 part just gets cut off. This leaves us with just 1. In other words, it's 6 divided by 4, rounded down. 74 | 75 | ## Fractions with Fixed-Point 76 | 77 | So, we know binary and we know how to bit shift. But all of the values so far are just integers. When do the fractions come in? Well, they don't actually. 78 | 79 | Programmers before us were pretty clever. If all we have to work with are integers, but we need fractions, what do we do? Well, we can just pretend that a portion of the bits are fractional anyway, and that works well enough! 80 | 81 | So, let's say we set aside the rightmost 4 bits for a fraction. Now let's try counting again! 82 | 83 | ```c 84 | 00000000 // 0/16 85 | 00000001 // 1/16 86 | 00000010 // 2/16 87 | 00000011 // 3/16 88 | 00000100 // 4/16 89 | 00000101 // 5/16 90 | 00000110 // 6/16 91 | 00000111 // 7/16 92 | 00001000 // 8/16 93 | 00001001 // 9/16 94 | 00001010 // 10/16 95 | 00001011 // 11/16 96 | ``` 97 | 98 | And so on. These aren’t *actually* 1/16 and so on, but we’re pretending that they are. We dedicated 4 bits here, so we get "2 to the power of 4" as the denominator, and we're counting the numerator just the same as before. Once we hit the 5th bit going left, we've arrived at 1 proper. 99 | 100 | Another way to think of it is that the right 4 bits are the "fractional segment", and the left 4 bits are the "integer segment". 101 | 102 | If we want to use this for an input that needs a proper integer (instead of a fixed-point representation) then we shift right by 4 bits. This rounds the number down to the nearest integer. 103 | 104 | This would typically be referred to as "4.4f fixed-point". 4 bits for the integer, and 4 bits for the fraction. That's assuming it's unsigned (only positive numbers). If we need negative numbers, then we take away one bit (the leftmost) for that, so we would say that it's "signed 3.4f fixed-point". 105 | 106 | However, the maximum value here is painfully small. I've been using 8 bits for readability, but usually you’d want the biggest data type available for your system. For the GBA, that would be an `int`, which is 32 bits, or 4 bytes. So if we use 4 bits for the fraction, and it's a signed `int` data type, then that would be "signed 27.4f fixed-point". 107 | 108 | ## A Practical Example 109 | 110 | Let's say we have a player sprite, with an X and Y position. What speed should we move it at? 2 pixels per frame is too fast, but 1 pixel per frame is too slow. Why don’t we try... 1 and 3/8 pixels per frame. This time we're using 3 bits for our fixed-point. 111 | 112 | ```c 113 | // a function elsewhere in code, which needs the ONSCREEN x and y position 114 | void display_player(int x, int y); 115 | 116 | // player coordinates use signed 28.3f fixed-point format 117 | const int player_fp = 3; 118 | 119 | // 1 and 5/8, written verbosely for demonstration purposes 120 | int player_speed = (1 << player_fp) + ((5 << player_fp) / 8); 121 | 122 | // let's start the player at (5, 6) on the screen 123 | // shift both of these values left to account for the fixed-point 124 | signed int player_x = 5 << player_fp; 125 | signed int player_y = 6 << player_fp; 126 | 127 | ... // skip ahead to the main game loop 128 | 129 | // adjust the player’s position based on input 130 | if key_is_down(KEY_LEFT) { 131 | player_x -= player_speed; 132 | } else if key_is_down(KEY_RIGHT) { 133 | player_x += player_speed; 134 | } else if key_is_down(KEY_UP) { 135 | player_y -= player_speed; 136 | } else if key_is_down(KEY_DOWN) { 137 | player_y += player_speed; 138 | } 139 | 140 | // we need their onscreen x and y position here, not the fixed-point representation 141 | display_player(player_x >> player_fp, player_y >> player_fp); 142 | ``` 143 | 144 | Let's break this down: 145 | 146 | First, we declare the number of bits we're using for the fractional denominator. Then, we initialize variables that use that denominator. Next, we work with those variables, until we need its integer component. Finally, we shift right. 147 | 148 | **Always comment your fixed-point. Always always always comment.** It will save many headaches, for you and for anyone reading your code. 149 | 150 | All player location values here use a signed 28.3 fixed-point format, but other values, such as player health or stamina, could use different fixed-point formats, or they could just avoid fixed-point entirely. It's up to you! One set of numbers could use unsigned 16.16f, another set could use signed 30.1f, and so on. It really depends on whatever you need for the numbers that you're working with. 151 | 152 | When shifting right, be careful not to shift onto the variables themselves. For example, it would be a mistake here to do something like: 153 | 154 | ```c 155 | player_x = player_x >> player_fp; // DON'T DO THIS 156 | ``` 157 | 158 | Because you'd be destroying the fractional component, which needs to persist on to the next frame. Instead, you'd either want to shift while using `player_x` as an argument, or you'd want to initialize a separate variable and then shift when assigning to that. You typically only want the right-shifted version at the very end, for outputs. 159 | 160 | ## Addition and Subtraction 161 | 162 | Before adding or subtracting fixed-point numbers, you need to make the denominators match. You can’t just add 1/2 and 3/4 together without first turning 1/2 into 2/4. So, let’s say we have these two variables: 163 | 164 | ```c 165 | // variable 'a' uses an unsigned 27.5f fixed-point format 166 | const int a_fp = 5; 167 | unsigned int a = 3 << a_fp; 168 | 169 | // variable 'b' uses an unsigned 16.16f fixed-point format 170 | const int b_fp = 16; 171 | unsigned int b = 4 << b_fp; 172 | ``` 173 | 174 | These equal 3 and 4, but they’re using different fixed-point representations. If we want to add them together, we need to shift one of them around to have the same format as the other. That looks something like this: 175 | 176 | ```c 177 | // variable 'c' uses the fixed-point format from variable 'b' 178 | unsigned int c = (a << (b_fp - a_fp)) + b; 179 | ``` 180 | 181 | First, we shift the variable `a` to match the fixed-point of variable `b`, based on the difference between the two fixed-points. Then we add. We could have shifted variable `b` to match the fixed-point of variable `a`, or we could have shifted both to an entirely new fixed-point. It’s open-ended to whatever precision is needed. 182 | 183 | Note that we use multiple parentheses here; bit shifts do not follow the PEMDAS order of operations, so you will need an abundance of parentheses in order to tell the program exactly what order to follow. At least in C, the compiler will throw a warning if you don’t do this. Also note that you cannot shift by a negative number, it will just throw an error. 184 | 185 | ## Multiplication 186 | 187 | What if you want to multiply `a` and `b` from before? If you multiply two fixed-point numbers together, you will multiply the fixed-point along with it. In other words, the denominator gets multiplied! This is fine, it just means that you need to shift right after the multiplication. That looks something like this: 188 | 189 | ```c 190 | // variable 'c' uses the fixed-point format from variable 'b' 191 | unsigned int c = (a * b) >> a_fp; 192 | ``` 193 | 194 | With variable `a` having a fixed-point of 27.5f and variable `b` having a fixed-point of 16.16f, that gives us a fixed-point of 11.21f after multiplication (5 plus 16 in the denominator). We shift right by 5 bits to get back to 16.16f, but we could have shifted right by 16 bits to get to 27.5f if we wanted that instead. Again, it’s open to whatever precision is needed. 195 | 196 | It’s important to note that you don’t have infinite bits to work with. With an `int` value, you only have 32 bits lying around, and one of those bits might be needed for signing. Therefore, if you’re going to be multiplying fixed-point values, you need to be mindful of your fixed-point systems, otherwise it will quickly "overflow". Overflow is when you run out of bits, so the number clips to the left, outside of what can be contained. 197 | 198 | For example, if you multiply a 16.16f number by another 16.16f number, then that leaves you with 0.32f during the process of multiplication. That’s not even one bit for the integer segment! Be careful and plan out your fixed-points accordingly. There are workarounds for this, but they will either be slower or less precise. One option is to multiply into a larger data type that has 64 bits of space (slower, for the GBA at least). In C, you would want a `uint64_t` for that. Another option is to shift each value right by half of the fixed-point before multiplying (less precise). 199 | 200 | ## Division 201 | 202 | What about division? Well, you probably shouldn’t do that. That’s because if your system doesn’t have an FPU, it probably doesn’t have hardware-level division either. The GBA doesn’t have hardware-level division. 203 | 204 | As mentioned before, you can shift right, and this will divide by powers of 2, rounding down. Note that even when shifting negative numbers right, it will still round *down*, not towards 0. That means that -3 shifted right by 1 bit will become -2, not -1. 205 | 206 | Even though you can't do hardware-level division, there are usually creative workarounds. Think outside of the box for this one. How might you get the answer you want without properly dividing? You'd be surprised with just how much division you can get rid of. 207 | 208 | If you really must divide, you would multiply the numerator by the fixed-point first, *before* dividing. 209 | 210 | ## Converting between fixed and floating point 211 | 212 | Now you have a way to do mathematical operations efficiently. How do you set the initial values in a convenient way? How do you print the values in a way that is easier to understand than very big integer values? 213 | 214 | Well, you can convert between fixed and floating point easily: 215 | 216 | ```c 217 | const int player_fp = 3; 218 | 219 | static inline int player_float2fixed(float value) 220 | { 221 | return (int)(value * (1 << player_fp)); 222 | } 223 | 224 | static inline float player_fixed2float(int value) 225 | { 226 | return value / (float)(1 << player_fp); 227 | } 228 | 229 | // Macro version of the functions, for situations where you can't use functions 230 | #define PLAYER_FLOAT2FIXED(value) (int)((value) * (1 << (player_fp))) 231 | #define PLAYER_FIXED2FLOAT(value) ((value) / (float)(1 << (player_fp))) 232 | 233 | int setup(void) 234 | { 235 | int player_x = player_float2fixed(1.23); 236 | int player_y = PLAYER_FLOAT2FIXED(2.35); 237 | 238 | printf("Player X: %f\n", player_fixed2float(player_x); 239 | printf("Player Y: %f\n", PLAYER_FIXED2FLOAT(player_y); 240 | } 241 | ``` 242 | 243 | Remember that those are floating point operations, so they will be slow. There is an exception: if you use `constexpr` or if the compiler detects that an expression is constant, it will calculate it at compile time automatically. This is very useful for setting initial fixed point values from floating point values. 244 | 245 | ```c 246 | int player_x, player_y; 247 | 248 | constexpr int player_start_x = player_float2fixed(1.23); // Only in C++ 249 | const int player_start_y = PLAYER_FLOAT2FIXED(2.35); 250 | 251 | int setup(void) 252 | { 253 | player_x = player_start_x; 254 | player_y = player_start_y; 255 | } 256 | ``` 257 | 258 | And there you go! You now know everything needed to do fixed-point math. Good luck! 259 | 260 | ## FAQ 261 | ### What if I want to round to the nearest integer, or round up? 262 | 263 | To round to the nearest integer, add 0.5 (half of the denominator), then shift right. To round up, add "the denominator minus one", then shift right. 264 | 265 | ### Why are my numbers slightly off? 266 | 267 | It’s probably because of rounding errors. Not only your final values, but the in-between values as well. This entire process can involve rounding upon rounding, and this can accumulate over time to produce weird results. 268 | 269 | ### What about arithmetic between signed and unsigned variables? 270 | 271 | Unsigned values will equal their signed counterparts all the way up until the leftmost bit is set. The math will still be as expected, as long as the leftmost bit of *the unsigned value* is 0. Note that the variable holding the result should probably be signed. If the unsigned variable is so large that the leftmost bit is set, then your result might overflow. 272 | 273 | ### Shouldn't the leftmost sign bit move around with the rest of the bits, when shifting? 274 | 275 | Most languages, besides assembly, will handle the sign bit based on whether or not the variable is initialized as signed or unsigned. In ARM assembly, there are separate shifts depending on if you want to preserve the sign bit or move it with everything else. 276 | 277 | ### What about endianness? 278 | 279 | Endianness is surprisingly not as relevant here as you'd think, at least if you're using a major programming language. I'm not going to describe endianness here. 280 | 281 | ### Is it "fixed-point" or "fixed point"? 282 | 283 | Going to the Wikipedia page for [fixed-point arithmetic](#https://en.wikipedia.org/wiki/Fixed-point_arithmetic) and just doing a ctrl-f search, I can see 79 instances of "fixed-point" and 28 instances of "fixed point". So, it doesn't matter, just pick whichever looks prettier to you. 284 | 285 | -------------------------------------------------------------------------------- /content/fonts/interweb/Inter-Black.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gbadev-org/gbadoc/13f4a26a2925bcc17f21d813188fab57eef2497a/content/fonts/interweb/Inter-Black.woff -------------------------------------------------------------------------------- /content/fonts/interweb/Inter-Black.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gbadev-org/gbadoc/13f4a26a2925bcc17f21d813188fab57eef2497a/content/fonts/interweb/Inter-Black.woff2 -------------------------------------------------------------------------------- /content/fonts/interweb/Inter-BlackItalic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gbadev-org/gbadoc/13f4a26a2925bcc17f21d813188fab57eef2497a/content/fonts/interweb/Inter-BlackItalic.woff -------------------------------------------------------------------------------- /content/fonts/interweb/Inter-BlackItalic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gbadev-org/gbadoc/13f4a26a2925bcc17f21d813188fab57eef2497a/content/fonts/interweb/Inter-BlackItalic.woff2 -------------------------------------------------------------------------------- /content/fonts/interweb/Inter-Bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gbadev-org/gbadoc/13f4a26a2925bcc17f21d813188fab57eef2497a/content/fonts/interweb/Inter-Bold.woff -------------------------------------------------------------------------------- /content/fonts/interweb/Inter-Bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gbadev-org/gbadoc/13f4a26a2925bcc17f21d813188fab57eef2497a/content/fonts/interweb/Inter-Bold.woff2 -------------------------------------------------------------------------------- /content/fonts/interweb/Inter-BoldItalic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gbadev-org/gbadoc/13f4a26a2925bcc17f21d813188fab57eef2497a/content/fonts/interweb/Inter-BoldItalic.woff -------------------------------------------------------------------------------- /content/fonts/interweb/Inter-BoldItalic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gbadev-org/gbadoc/13f4a26a2925bcc17f21d813188fab57eef2497a/content/fonts/interweb/Inter-BoldItalic.woff2 -------------------------------------------------------------------------------- /content/fonts/interweb/Inter-ExtraBold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gbadev-org/gbadoc/13f4a26a2925bcc17f21d813188fab57eef2497a/content/fonts/interweb/Inter-ExtraBold.woff -------------------------------------------------------------------------------- /content/fonts/interweb/Inter-ExtraBold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gbadev-org/gbadoc/13f4a26a2925bcc17f21d813188fab57eef2497a/content/fonts/interweb/Inter-ExtraBold.woff2 -------------------------------------------------------------------------------- /content/fonts/interweb/Inter-ExtraBoldItalic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gbadev-org/gbadoc/13f4a26a2925bcc17f21d813188fab57eef2497a/content/fonts/interweb/Inter-ExtraBoldItalic.woff -------------------------------------------------------------------------------- /content/fonts/interweb/Inter-ExtraBoldItalic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gbadev-org/gbadoc/13f4a26a2925bcc17f21d813188fab57eef2497a/content/fonts/interweb/Inter-ExtraBoldItalic.woff2 -------------------------------------------------------------------------------- /content/fonts/interweb/Inter-ExtraLight.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gbadev-org/gbadoc/13f4a26a2925bcc17f21d813188fab57eef2497a/content/fonts/interweb/Inter-ExtraLight.woff -------------------------------------------------------------------------------- /content/fonts/interweb/Inter-ExtraLight.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gbadev-org/gbadoc/13f4a26a2925bcc17f21d813188fab57eef2497a/content/fonts/interweb/Inter-ExtraLight.woff2 -------------------------------------------------------------------------------- /content/fonts/interweb/Inter-ExtraLightItalic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gbadev-org/gbadoc/13f4a26a2925bcc17f21d813188fab57eef2497a/content/fonts/interweb/Inter-ExtraLightItalic.woff -------------------------------------------------------------------------------- /content/fonts/interweb/Inter-ExtraLightItalic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gbadev-org/gbadoc/13f4a26a2925bcc17f21d813188fab57eef2497a/content/fonts/interweb/Inter-ExtraLightItalic.woff2 -------------------------------------------------------------------------------- /content/fonts/interweb/Inter-Italic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gbadev-org/gbadoc/13f4a26a2925bcc17f21d813188fab57eef2497a/content/fonts/interweb/Inter-Italic.woff -------------------------------------------------------------------------------- /content/fonts/interweb/Inter-Italic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gbadev-org/gbadoc/13f4a26a2925bcc17f21d813188fab57eef2497a/content/fonts/interweb/Inter-Italic.woff2 -------------------------------------------------------------------------------- /content/fonts/interweb/Inter-Light.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gbadev-org/gbadoc/13f4a26a2925bcc17f21d813188fab57eef2497a/content/fonts/interweb/Inter-Light.woff -------------------------------------------------------------------------------- /content/fonts/interweb/Inter-Light.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gbadev-org/gbadoc/13f4a26a2925bcc17f21d813188fab57eef2497a/content/fonts/interweb/Inter-Light.woff2 -------------------------------------------------------------------------------- /content/fonts/interweb/Inter-LightItalic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gbadev-org/gbadoc/13f4a26a2925bcc17f21d813188fab57eef2497a/content/fonts/interweb/Inter-LightItalic.woff -------------------------------------------------------------------------------- /content/fonts/interweb/Inter-LightItalic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gbadev-org/gbadoc/13f4a26a2925bcc17f21d813188fab57eef2497a/content/fonts/interweb/Inter-LightItalic.woff2 -------------------------------------------------------------------------------- /content/fonts/interweb/Inter-Medium.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gbadev-org/gbadoc/13f4a26a2925bcc17f21d813188fab57eef2497a/content/fonts/interweb/Inter-Medium.woff -------------------------------------------------------------------------------- /content/fonts/interweb/Inter-Medium.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gbadev-org/gbadoc/13f4a26a2925bcc17f21d813188fab57eef2497a/content/fonts/interweb/Inter-Medium.woff2 -------------------------------------------------------------------------------- /content/fonts/interweb/Inter-MediumItalic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gbadev-org/gbadoc/13f4a26a2925bcc17f21d813188fab57eef2497a/content/fonts/interweb/Inter-MediumItalic.woff -------------------------------------------------------------------------------- /content/fonts/interweb/Inter-MediumItalic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gbadev-org/gbadoc/13f4a26a2925bcc17f21d813188fab57eef2497a/content/fonts/interweb/Inter-MediumItalic.woff2 -------------------------------------------------------------------------------- /content/fonts/interweb/Inter-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gbadev-org/gbadoc/13f4a26a2925bcc17f21d813188fab57eef2497a/content/fonts/interweb/Inter-Regular.woff -------------------------------------------------------------------------------- /content/fonts/interweb/Inter-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gbadev-org/gbadoc/13f4a26a2925bcc17f21d813188fab57eef2497a/content/fonts/interweb/Inter-Regular.woff2 -------------------------------------------------------------------------------- /content/fonts/interweb/Inter-SemiBold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gbadev-org/gbadoc/13f4a26a2925bcc17f21d813188fab57eef2497a/content/fonts/interweb/Inter-SemiBold.woff -------------------------------------------------------------------------------- /content/fonts/interweb/Inter-SemiBold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gbadev-org/gbadoc/13f4a26a2925bcc17f21d813188fab57eef2497a/content/fonts/interweb/Inter-SemiBold.woff2 -------------------------------------------------------------------------------- /content/fonts/interweb/Inter-SemiBoldItalic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gbadev-org/gbadoc/13f4a26a2925bcc17f21d813188fab57eef2497a/content/fonts/interweb/Inter-SemiBoldItalic.woff -------------------------------------------------------------------------------- /content/fonts/interweb/Inter-SemiBoldItalic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gbadev-org/gbadoc/13f4a26a2925bcc17f21d813188fab57eef2497a/content/fonts/interweb/Inter-SemiBoldItalic.woff2 -------------------------------------------------------------------------------- /content/fonts/interweb/Inter-Thin.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gbadev-org/gbadoc/13f4a26a2925bcc17f21d813188fab57eef2497a/content/fonts/interweb/Inter-Thin.woff -------------------------------------------------------------------------------- /content/fonts/interweb/Inter-Thin.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gbadev-org/gbadoc/13f4a26a2925bcc17f21d813188fab57eef2497a/content/fonts/interweb/Inter-Thin.woff2 -------------------------------------------------------------------------------- /content/fonts/interweb/Inter-ThinItalic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gbadev-org/gbadoc/13f4a26a2925bcc17f21d813188fab57eef2497a/content/fonts/interweb/Inter-ThinItalic.woff -------------------------------------------------------------------------------- /content/fonts/interweb/Inter-ThinItalic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gbadev-org/gbadoc/13f4a26a2925bcc17f21d813188fab57eef2497a/content/fonts/interweb/Inter-ThinItalic.woff2 -------------------------------------------------------------------------------- /content/fonts/interweb/Inter-italic.var.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gbadev-org/gbadoc/13f4a26a2925bcc17f21d813188fab57eef2497a/content/fonts/interweb/Inter-italic.var.woff2 -------------------------------------------------------------------------------- /content/fonts/interweb/Inter-roman.var.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gbadev-org/gbadoc/13f4a26a2925bcc17f21d813188fab57eef2497a/content/fonts/interweb/Inter-roman.var.woff2 -------------------------------------------------------------------------------- /content/fonts/interweb/Inter.var.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gbadev-org/gbadoc/13f4a26a2925bcc17f21d813188fab57eef2497a/content/fonts/interweb/Inter.var.woff2 -------------------------------------------------------------------------------- /content/fonts/interweb/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016-2020 The Inter Project Authors. 2 | "Inter" is trademark of Rasmus Andersson. 3 | https://github.com/rsms/inter 4 | 5 | This Font Software is licensed under the SIL Open Font License, Version 1.1. 6 | This license is copied below, and is also available with a FAQ at: 7 | http://scripts.sil.org/OFL 8 | 9 | ----------------------------------------------------------- 10 | SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 11 | ----------------------------------------------------------- 12 | 13 | PREAMBLE 14 | The goals of the Open Font License (OFL) are to stimulate worldwide 15 | development of collaborative font projects, to support the font creation 16 | efforts of academic and linguistic communities, and to provide a free and 17 | open framework in which fonts may be shared and improved in partnership 18 | with others. 19 | 20 | The OFL allows the licensed fonts to be used, studied, modified and 21 | redistributed freely as long as they are not sold by themselves. The 22 | fonts, including any derivative works, can be bundled, embedded, 23 | redistributed and/or sold with any software provided that any reserved 24 | names are not used by derivative works. The fonts and derivatives, 25 | however, cannot be released under any other type of license. The 26 | requirement for fonts to remain under this license does not apply 27 | to any document created using the fonts or their derivatives. 28 | 29 | DEFINITIONS 30 | "Font Software" refers to the set of files released by the Copyright 31 | Holder(s) under this license and clearly marked as such. This may 32 | include source files, build scripts and documentation. 33 | 34 | "Reserved Font Name" refers to any names specified as such after the 35 | copyright statement(s). 36 | 37 | "Original Version" refers to the collection of Font Software components as 38 | distributed by the Copyright Holder(s). 39 | 40 | "Modified Version" refers to any derivative made by adding to, deleting, 41 | or substituting -- in part or in whole -- any of the components of the 42 | Original Version, by changing formats or by porting the Font Software to a 43 | new environment. 44 | 45 | "Author" refers to any designer, engineer, programmer, technical 46 | writer or other person who contributed to the Font Software. 47 | 48 | PERMISSION AND CONDITIONS 49 | Permission is hereby granted, free of charge, to any person obtaining 50 | a copy of the Font Software, to use, study, copy, merge, embed, modify, 51 | redistribute, and sell modified and unmodified copies of the Font 52 | Software, subject to the following conditions: 53 | 54 | 1) Neither the Font Software nor any of its individual components, 55 | in Original or Modified Versions, may be sold by itself. 56 | 57 | 2) Original or Modified Versions of the Font Software may be bundled, 58 | redistributed and/or sold with any software, provided that each copy 59 | contains the above copyright notice and this license. These can be 60 | included either as stand-alone text files, human-readable headers or 61 | in the appropriate machine-readable metadata fields within text or 62 | binary files as long as those fields can be easily viewed by the user. 63 | 64 | 3) No Modified Version of the Font Software may use the Reserved Font 65 | Name(s) unless explicit written permission is granted by the corresponding 66 | Copyright Holder. This restriction only applies to the primary font name as 67 | presented to the users. 68 | 69 | 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font 70 | Software shall not be used to promote, endorse or advertise any 71 | Modified Version, except to acknowledge the contribution(s) of the 72 | Copyright Holder(s) and the Author(s) or with their explicit written 73 | permission. 74 | 75 | 5) The Font Software, modified or unmodified, in part or in whole, 76 | must be distributed entirely under this license, and must not be 77 | distributed under any other license. The requirement for fonts to 78 | remain under this license does not apply to any document created 79 | using the Font Software. 80 | 81 | TERMINATION 82 | This license becomes null and void if any of the above conditions are 83 | not met. 84 | 85 | DISCLAIMER 86 | THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 87 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF 88 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT 89 | OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE 90 | COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 91 | INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL 92 | DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 93 | FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM 94 | OTHER DEALINGS IN THE FONT SOFTWARE. 95 | -------------------------------------------------------------------------------- /content/fonts/interweb/inter.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'Inter'; 3 | font-style: normal; 4 | font-weight: 100; 5 | font-display: swap; 6 | src: url("Inter-Thin.woff2?v=3.18") format("woff2"), 7 | url("Inter-Thin.woff?v=3.18") format("woff"); 8 | } 9 | @font-face { 10 | font-family: 'Inter'; 11 | font-style: italic; 12 | font-weight: 100; 13 | font-display: swap; 14 | src: url("Inter-ThinItalic.woff2?v=3.18") format("woff2"), 15 | url("Inter-ThinItalic.woff?v=3.18") format("woff"); 16 | } 17 | 18 | @font-face { 19 | font-family: 'Inter'; 20 | font-style: normal; 21 | font-weight: 200; 22 | font-display: swap; 23 | src: url("Inter-ExtraLight.woff2?v=3.18") format("woff2"), 24 | url("Inter-ExtraLight.woff?v=3.18") format("woff"); 25 | } 26 | @font-face { 27 | font-family: 'Inter'; 28 | font-style: italic; 29 | font-weight: 200; 30 | font-display: swap; 31 | src: url("Inter-ExtraLightItalic.woff2?v=3.18") format("woff2"), 32 | url("Inter-ExtraLightItalic.woff?v=3.18") format("woff"); 33 | } 34 | 35 | @font-face { 36 | font-family: 'Inter'; 37 | font-style: normal; 38 | font-weight: 300; 39 | font-display: swap; 40 | src: url("Inter-Light.woff2?v=3.18") format("woff2"), 41 | url("Inter-Light.woff?v=3.18") format("woff"); 42 | } 43 | @font-face { 44 | font-family: 'Inter'; 45 | font-style: italic; 46 | font-weight: 300; 47 | font-display: swap; 48 | src: url("Inter-LightItalic.woff2?v=3.18") format("woff2"), 49 | url("Inter-LightItalic.woff?v=3.18") format("woff"); 50 | } 51 | 52 | @font-face { 53 | font-family: 'Inter'; 54 | font-style: normal; 55 | font-weight: 400; 56 | font-display: swap; 57 | src: url("Inter-Regular.woff2?v=3.18") format("woff2"), 58 | url("Inter-Regular.woff?v=3.18") format("woff"); 59 | } 60 | @font-face { 61 | font-family: 'Inter'; 62 | font-style: italic; 63 | font-weight: 400; 64 | font-display: swap; 65 | src: url("Inter-Italic.woff2?v=3.18") format("woff2"), 66 | url("Inter-Italic.woff?v=3.18") format("woff"); 67 | } 68 | 69 | @font-face { 70 | font-family: 'Inter'; 71 | font-style: normal; 72 | font-weight: 500; 73 | font-display: swap; 74 | src: url("Inter-Medium.woff2?v=3.18") format("woff2"), 75 | url("Inter-Medium.woff?v=3.18") format("woff"); 76 | } 77 | @font-face { 78 | font-family: 'Inter'; 79 | font-style: italic; 80 | font-weight: 500; 81 | font-display: swap; 82 | src: url("Inter-MediumItalic.woff2?v=3.18") format("woff2"), 83 | url("Inter-MediumItalic.woff?v=3.18") format("woff"); 84 | } 85 | 86 | @font-face { 87 | font-family: 'Inter'; 88 | font-style: normal; 89 | font-weight: 600; 90 | font-display: swap; 91 | src: url("Inter-SemiBold.woff2?v=3.18") format("woff2"), 92 | url("Inter-SemiBold.woff?v=3.18") format("woff"); 93 | } 94 | @font-face { 95 | font-family: 'Inter'; 96 | font-style: italic; 97 | font-weight: 600; 98 | font-display: swap; 99 | src: url("Inter-SemiBoldItalic.woff2?v=3.18") format("woff2"), 100 | url("Inter-SemiBoldItalic.woff?v=3.18") format("woff"); 101 | } 102 | 103 | @font-face { 104 | font-family: 'Inter'; 105 | font-style: normal; 106 | font-weight: 700; 107 | font-display: swap; 108 | src: url("Inter-Bold.woff2?v=3.18") format("woff2"), 109 | url("Inter-Bold.woff?v=3.18") format("woff"); 110 | } 111 | @font-face { 112 | font-family: 'Inter'; 113 | font-style: italic; 114 | font-weight: 700; 115 | font-display: swap; 116 | src: url("Inter-BoldItalic.woff2?v=3.18") format("woff2"), 117 | url("Inter-BoldItalic.woff?v=3.18") format("woff"); 118 | } 119 | 120 | @font-face { 121 | font-family: 'Inter'; 122 | font-style: normal; 123 | font-weight: 800; 124 | font-display: swap; 125 | src: url("Inter-ExtraBold.woff2?v=3.18") format("woff2"), 126 | url("Inter-ExtraBold.woff?v=3.18") format("woff"); 127 | } 128 | @font-face { 129 | font-family: 'Inter'; 130 | font-style: italic; 131 | font-weight: 800; 132 | font-display: swap; 133 | src: url("Inter-ExtraBoldItalic.woff2?v=3.18") format("woff2"), 134 | url("Inter-ExtraBoldItalic.woff?v=3.18") format("woff"); 135 | } 136 | 137 | @font-face { 138 | font-family: 'Inter'; 139 | font-style: normal; 140 | font-weight: 900; 141 | font-display: swap; 142 | src: url("Inter-Black.woff2?v=3.18") format("woff2"), 143 | url("Inter-Black.woff?v=3.18") format("woff"); 144 | } 145 | @font-face { 146 | font-family: 'Inter'; 147 | font-style: italic; 148 | font-weight: 900; 149 | font-display: swap; 150 | src: url("Inter-BlackItalic.woff2?v=3.18") format("woff2"), 151 | url("Inter-BlackItalic.woff?v=3.18") format("woff"); 152 | } 153 | 154 | /* ------------------------------------------------------- 155 | Variable font. 156 | Usage: 157 | 158 | html { font-family: 'Inter', sans-serif; } 159 | @supports (font-variation-settings: normal) { 160 | html { font-family: 'Inter var', sans-serif; } 161 | } 162 | */ 163 | @font-face { 164 | font-family: 'Inter var'; 165 | font-weight: 100 900; 166 | font-display: swap; 167 | font-style: normal; 168 | font-named-instance: 'Regular'; 169 | src: url("Inter-roman.var.woff2?v=3.18") format("woff2"); 170 | } 171 | @font-face { 172 | font-family: 'Inter var'; 173 | font-weight: 100 900; 174 | font-display: swap; 175 | font-style: italic; 176 | font-named-instance: 'Italic'; 177 | src: url("Inter-italic.var.woff2?v=3.18") format("woff2"); 178 | } 179 | 180 | 181 | /* -------------------------------------------------------------------------- 182 | [EXPERIMENTAL] Multi-axis, single variable font. 183 | 184 | Slant axis is not yet widely supported (as of February 2019) and thus this 185 | multi-axis single variable font is opt-in rather than the default. 186 | 187 | When using this, you will probably need to set font-variation-settings 188 | explicitly, e.g. 189 | 190 | * { font-variation-settings: "slnt" 0deg } 191 | .italic { font-variation-settings: "slnt" 10deg } 192 | 193 | */ 194 | @font-face { 195 | font-family: 'Inter var experimental'; 196 | font-weight: 100 900; 197 | font-display: swap; 198 | font-style: oblique 0deg 10deg; 199 | src: url("Inter.var.woff2?v=3.18") format("woff2"); 200 | } 201 | -------------------------------------------------------------------------------- /content/graphics.md: -------------------------------------------------------------------------------- 1 | # Graphics Hardware Overview 2 | 3 | The GBA has a TFT color LCD that is 240 x 160 pixels in size and has a refresh rate of exactly 280,896 cpu cycles per frame, or around 59.73 hz. Most GBA programs will need to structure themselves around this refresh rate. 4 | 5 | 6 | 7 | 8 | 9 | 10 | Each refresh consists of a 160 scanline vertical draw (VDraw) period followed by a 68 scanline blank (VBlank) period. Furthermore, each of these scanlines consists of a 1004 cycle draw period (HDraw) followed by a 228 cycle blank period (HBlank). 11 | 12 | During the HDraw and VDraw periods the graphics hardware processes background and obj (sprite) data and draws it on the screen, while the HBlank and VBlank periods are left open so that program code can modify background and obj data without risk of creating graphical artifacts. 13 | 14 | ## Video Modes 15 | 16 | Exactly what the GBA draws on screen depends largely on the current video mode (also sometimes referred to as the _screen mode_ or _graphics mode_). The GBA has 6 such modes, some of which are bitmap-based and some of which are tile-based. The video mode is set by the bottom three bits of the hardware register known as [REG_DISPCNT](registers.md#REG_DISPCNT). Background data is handled differently depending on what mode is enabled. Backgrounds can either be [text backgrounds](backgrounds.md#text-backgrounds) (tile based), [rotate-scale backgrounds](backgrounds.md#scalerotate-backgrounds) (tile based backgrounds that can be transformed), or [bitmap backgrounds](backgrounds.md#bitmapped-backgrounds). The number of sprites available on screen is also dependent on the mode; modes with tile-based backgrounds support 128 sprites, while modes with bitmapped backgrounds will only support 64 sprites. 17 | 18 | Enabling objs and one or more backgrounds in [REG_DISPCNT](registers.md#REG_DISPCNT) will cause the GBA to draw the specified backgrounds and objs in order of priority. 19 | 20 | ### Mode 0 21 | 22 | In this mode, four text background layers can be shown. In this mode backgrounds 0 - 3 all count as ["text"](backgrounds.md#text-backgrounds) backgrounds, and cannot be scaled or rotated. Check out the section on [text backgrounds](backgrounds.md#text-backgrounds) for details on this. 23 | 24 | ### Mode 1 25 | 26 | This mode is similar in most respects to Mode 0, the main difference being that only 3 backgrounds are accessible -- 0, 1, and 2. Bgs 0 and 1 are [text backgrounds](backgrounds.md#text-backgrounds), while bg 2 is a [rotation/scaling](backgrounds.md#scalerotate-backgrounds) background. 27 | 28 | ### Mode 2 29 | 30 | Like modes 0 and 1, this uses tiled backgrounds. It uses backgrounds 2 and 3, both of which are [rotate/scale backgrounds](backgrounds.md#scalerotate-backgrounds). 31 | 32 | ### Mode 3 33 | 34 | Standard 16-bit bitmapped (non-paletted) 240x160 mode. The map starts at `0x06000000` and is `0x12C00` bytes long. See the [Color Format](#color-format) table above for the format of these bytes. 35 | 36 | This allows the full color range to be displayed at once. Unfortunately, the frame buffer in this mode is too large for page flipping to be possible. One option to get around this would be to copy a frame buffer from work RAM into VRAM during the retrace, or (so I have heard) to use [DMA3](registers.md#REG_DMA3CNT) with the start mode bits set to 11. 37 | 38 | ### Mode 4 39 | 40 | 8-Bit paletted bitmapped mode at 240x160. The bitmap starts at either `0x06000000` or `0x0600A000`, depending on bit 4 of [REG_DISPCNT](registers.md#REG_DISPCNT). Swapping the map and drawing in the one that isn't displayed allows for page flipping techniques to be used. The palette is at `0x05000000`, and contains 256 16-bit [color entries](#color-format). 41 | 42 | ### Mode 5 43 | 44 | This is another 16-bit bitmapped mode, but at a smaller resolution of 160x128. The display starts at the upper left hand corner of the screen, but can be shifted using the rotation and scaling registers for BG2. The advantage of using this mode is presumably that there are two frame buffers available, and this can be used to perform page flipping effects which cannot be done in mode 3 due to the smaller memory requirements of mode 5. Bit 3 of [REG_DISPCNT](registers.md#REG_DISPCNT) sets the start of the frame buffer to `0x06000000` when bit 3 is zero, and `0x0600A000` when bit 3 is one. 45 | 46 | ## Color Format 47 | 48 | All colors (both paletted and bitmapped) are represented as a 16 bit value, using 5 bits for red, green, and blue, and ignoring bit 15. In the case of paletted memory, pixels in an image are represented as 8 bit or 4 bit indices into the [palette RAM](#Palette) starting at `0x05000000` for backgrounds and `0x05002000` for sprites. Each palette is a table consisiting of 256 16-bit color entries. In the case of the bitmapped backgrounds in modes 3 and 4, pixels are represented as the 16-bit color values themselves. 49 | 50 | 51 |
F 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 |
20 |
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 |
25 | 26 | | Bits | Description | 27 | |---------|---------------------------------------------------------| 28 | | 0-7 (J) | Y co-ordinate of the sprite (pixels). Note that for regular sprites, this is the y coordinate of the upper left corner. For rotate/scale sprites, this is the y coordinate of the sprite's center. center . Note on Coordinates: The values actually wrap around: to achieve a -1 y coordinate, use y = 255. 29 | | 8 (R) | Rotation/Scaling on/off 30 | | 9 (D) | `0` = sprite is single sized;
`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 |
41 |
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 |
46 | 47 | | Bits | Description | 48 | |---------|---------------------------------------------------------| 49 | | 0-8 (I) | X coordinate of the sprite (pixels). For regular sprites, this is the x coordinate of the upper left corner. For rotate/scale sprites, this is the x coordinate of the sprite's center. Note on coordinates: The values actually wrap around. To achieve a -1 x, use x = 511. 50 | | C (H) | The flip horizinal bit 51 | | D (V) | The flip vertical bit 52 | | 9-D (F) | For rotation scaling sprites, the index into the rotation data to be used for that sprite. This index can be from 0 - 31. The rotation/scaling data is located in OAM [attribute 3](#attr3) (bytes 7 and 8). However, instead of the rotation and scaling data going with the corresponding sprite, it is separated accross four sequential sprites. This index can be thought of as referencing into an array of four-sprite blocks, 32 bytes each. 53 | | E-F (S) |

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:

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

54 | 55 | 56 | 57 | 58 | ## Bytes 5 and 6 (Attribute 2) 59 | 60 |
61 |
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 T
63 |
64 | 65 | | Bits | Description | 66 | |---------|---------------------------------------------------------| 67 | | 0-9 (T) |

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 |
76 |
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 F
78 |
79 | 80 | | Bits | Description | 81 | |---------|---------------------------------------------------------| 82 | | 0-7 (F) | Fraction. 83 | | 8-E (I) | Integer 84 | | F (S) | Sign bit 85 | 86 | These bytes control sprite rotation and scaling. Instead of the rotation and scaling data going with the corresponding sprite, it is separated accross four sequential sprites. This is indexed by bits 9 - 13 in [attribute 1](#attr1). Note that these are all relative to the center of the sprite (background rotation/scaling is relative to the upper left). Starting with sprite 0 and repeating every 4 sprites, they appear in the following order: 87 | 88 | * **Sprite 0, Attribute 3 - PA (DX)** 89 | 90 | Scales the sprite in the x direction by an amount equal to 1/(register value). Thus, a value of 1.0 results in the original image size, while a value of 2 is half as large, and a value of .5 is twice as large. 91 | 92 | * **Sprite 1, Attribute 3 - PB (DMX)** 93 | 94 | Shears the x coordinates of the sprite over y. A value of 0 will result in no shearing, a value of 1.00 will make the image appear to be sheared left going down the screen, and a value of -1 will make the image appear sheared right going down the screen. 95 | 96 | * **Sprite 2, Attribute 3 - PC (DY)** 97 | 98 | Shears the y coordinates of the sprite over x. A value of 0 will result in no shearing, a value of 1.00 will make the image appear to be sheared upwards to the right, and a value of -1 will make the image appear sheared downwards and to the right. 99 | 100 | * **Sprite 3, Attribute 3 - PD (DMY)** 101 | 102 | Scales the image in the y direction by an amount equal to 1/(register value). Thus, a value of 1.0 results in the original image size, while a value of 2 is half as large, and a value of .5 is twice as large. 103 | 104 | ## To Make a Sprite Rotate and Scale 105 | 106 | The basic form of the equations for rotating and scaling is as follows: 107 | 108 |
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 | --------------------------------------------------------------------------------