├── _01_introduction ├── architecture.md ├── assets │ ├── Game-Boy-Advance-SP-Mk1-Blue.jpg │ ├── Game-Boy-FL.jpg │ ├── Game-Boy-Micro.jpg │ ├── GameCube-Game-Boy-Player.jpg │ ├── Gameboy-Advance-SP-Mk2.jpg │ ├── Nintendo-DS-Fat-Blue.jpg │ ├── Nintendo-Game-Boy-Advance-Milky-Blue-FL.jpg │ ├── Nintendo-Game-Boy-Color-FL.jpg │ ├── QWzuQ54.jpg │ ├── ffta_agb_lcdA.png │ ├── ffta_agb_lcdB.png │ ├── ffta_agb_tv.png │ ├── ffta_pc_lcdA.png │ ├── ffta_pc_lcdB.png │ ├── ffta_pc_tv.png │ ├── ffta_title_lcdA.png │ ├── ffta_title_lcdB.png │ └── ktD5hLc.png ├── display.md ├── history.md └── sound.md ├── _02_setup ├── assets │ ├── mgba-0.png │ ├── path-0.png │ ├── path-1.png │ ├── path-2.png │ ├── path-3.png │ ├── path-4.png │ ├── vscode-0.png │ ├── vscode-1.png │ ├── vscode-10.png │ ├── vscode-11.png │ ├── vscode-12.png │ ├── vscode-13.png │ ├── vscode-14.png │ ├── vscode-15.png │ ├── vscode-16.png │ ├── vscode-17.png │ ├── vscode-18.png │ ├── vscode-19.png │ ├── vscode-2.png │ ├── vscode-20.png │ ├── vscode-21.png │ ├── vscode-22.png │ ├── vscode-3.png │ ├── vscode-4.png │ ├── vscode-5.png │ ├── vscode-6.png │ ├── vscode-7.png │ ├── vscode-8.png │ └── vscode-9.png ├── debugging.md ├── real-gba.md └── toolchain.md ├── _03_helloworld └── tonc.md ├── _config.yml ├── _includes ├── anchor_headings.html └── toc.html ├── _layouts ├── default.html └── post.html └── index.md /_01_introduction/architecture.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: "The Architecture" 4 | ordering: 2 5 | --- 6 | 7 | The GBA has a completely different machine architecture to the DMG/CGB. 8 | 9 | # The architecture 10 | 11 | The GBA was marketed as having a powerful 32-bit **RISC** processor. What does RISC mean? It stands for Reduce Instruction Set Computer. What does that mean? These days: not a lot. 12 | 13 | ## ARMv4t / ARM7TDMI 14 | 15 | The actual processor architecture used in the GBA is the ARM7TDMI. Supposedly the 7th generation of ARM's architecture (hence ARM7). Who is ARM? Advanced RISC Machines. 16 | 17 | What does TDMI stand for? Well that stands for: 18 | * 16-bit **T**humb instruction set support 19 | * The letter **D** 20 | * Hardware **M**ultiplication support 21 | * The letter **I** 22 | 23 | The primary instruction set for ARM7 is ARMv4 (the forth version of the ARM instruction set!), but because we have support for Thumb instructions the complete instruction set is ARMv4t. The naming convention is a little confusing. 24 | 25 | From here on these two instruction sets will be stylised as: thumb and ARM. 26 | 27 | > Theory trivia: The reason Nintendo used "RISC processor" in their marketing and not "ARM processor" could be because they didn't have a license to use ARM's trademark. 28 | 29 | ### Instruction sets 30 | 31 | This is actually super important for GBA stuff. The ARMv4t instruction set uses fixed-length instructions. ARM instructions are 32-bit, thumb instructions are 16-bit. 32 | 33 | The GBA is a 32-bit console, it will boot up reading 32-bit instructions to execute on its 32-bit CPU. But the bus to the cartridge is 16-bit! Which means all 32-bit reads will take two reads. That's not good for performance (maybe1). Also: 32-bits is a lot of bits taking up a lot of space, and the ROM chips on these cartridges cost money. 34 | 35 | The smaller 16-bit thumb instructions can be read across the cartridge's 16-bit bus in 1 read, the instructions are also much more dense in terms of bit storage, which (in theory) means smaller games, which means smaller ROM chips, so money saved. 36 | 37 | > Trivia: There is a reason why 16-bit thumb is so ideal for cheap cartridges on a 16-bit bus, and that's because ARM originally designed thumb with Nintendo and their cartridge consoles in mind. The ARM7TDMI itself (and the thumb instruction set) was published in 1994, some 7 years before the GBA's release date! 38 | 39 | ### Clock Speed 40 | 41 | The CPU runs at 2^24 cycles-per-second, which is 16.777216 megahertz (MHz). Some instructions take multiple cycles to execute, and some memory accesses take multiple cycles to complete. 42 | 43 | ## Random Access Memories 44 | 45 | But first: a bit about notation. 46 | 47 | |IEC name|Traditional name|Quantity |IEC symbol|LD symbol| 48 | |--------|----------------|----------|----------|---------| 49 | |Byte |Byte |8 bits |B |- | 50 | |Kibibyte|Kilobyte |1024 Bytes|KiB |K | 51 | |Mebibyte|Megabyte |1024 KiB |MiB |M | 52 | 53 | When required, we'll use the 1998 IEC names and symbols as they avoid ambiguity. The LD symbols are used in linker scripts, which will be important later. 54 | 55 | ## Cache? 56 | 57 | GBA has no cache. 58 | 59 | ### Internal RAM 60 | 61 | But isn't all the RAM internal? Well yes, but this is "internal" from the perspective of the CPU. 62 | 63 | The internal RAM is on the same physical package as the CPU. 64 | 65 | #### 32KiB Internal Work RAM 66 | 67 | IWRAM for short. This is fast RAM on a 32-bit bus: perfect for fast, optimised ARM instructions and stack memory. 68 | 69 | #### 96KiB Video RAM 70 | 71 | VRAM for short. This is where all the background and sprite graphics will live. You can only access this memory in units of 16-bits, so to write a single byte you have to first read 16-bits, modify the byte you're interested in, then write back 16-bits. Watch out for that. 72 | 73 | #### 1KiB Palette RAM 74 | 75 | PRAM? CRAM for colour RAM? There's no general short term for this RAM, so we'll just call it Palette RAM. This holds two palettes of 256 colours (Colours are 16-bit). One palette is used for background graphics, the other is used for sprite graphics. 76 | 77 | > Trivia: Yes the author is British. I will use the spelling "colour" for any written text, and "color" for any code. Did you notice how I spelled "optimised" above? 78 | 79 | #### 1KiB Object Attribute Memory 80 | 81 | OAM for short. This stores everything related to setting up hardware sprites for display. 82 | 83 | ### External RAM 84 | 85 | EWRAM for short. External from the CPU package, this RAM is still on the motherboard in its own little chip. 86 | 87 | 256KiB on a 16-bit bus. 32-bit accesses are automatically converted to two 16-bit access. Traditionally this is where the heap is placed for big allocations (because we have soooo much space with 256KiB). This is slower than IWRAM, and being 16-bits makes this more ideal for thumb instructions, rather than ARM instructions. 88 | 89 | ### Save RAM 90 | 91 | SRAM for short. This isn't actually part of the console, it resides in the game pak (the cartridge). This is only available on cartridges with a RAM chip on board. 8-bit accesses only, and the hardware does nothing to help if you want to access 16 or 32 bits. 92 | 93 | The 8-bit accesses makes this kind of slow. Intended for saving data, like a save file or something. 94 | 95 | Maxes out at 64KiB, but 32KiB is what you usually find out in the wild. 96 | 97 | ## Game Paks 98 | 99 | AKA: the cartridge, and the ROM. The maximum addressable size is 32MiB, however 64MiB cartridges do exist (those weird GBA video cartridges are such examples), and these achieve greater capacity through bank switching. 100 | 101 | Some cartridges have additional hardware on them, such as a real-time clock, a vibration motor, a tilt sensor, a freaking analogue TV tuner, and a crazy card-scanning accessory. 102 | 103 | ### Game Pak Prefetch 104 | 105 | This is a weird bit of hardware that is designed to try and speed up executing code from the Game Pak ROM. After fetching an instruction from ROM, whenever the CPU is not accessing the bus the prefetcher will further read up to an additional 8 16-bit values from the ROM, and store them internally. If the next access the CPU makes is within the area of ROM currently in the prefetch buffer then it will be read immediately (0 wait-cycles). 106 | 107 | In practical terms, this usually ends up with ROM thumb instructions in the prefetch buffer (because the next CPU read is usually the next instruction in ROM). 108 | 109 | This hardware feature requires explicitly enabling, and it's usually worth doing if you're executing anything from ROM. 110 | 111 | *** 112 | 113 | 1 Theoretically, if you're able to do something in ARM with 50% less instructions than in thumb, then executing ARM across 16-bit bus might not be such a bad performance hit. However, not all instructions are identical, so it is quite unlikely you'd naturally stumble across a scenario where this makes sense. 114 | -------------------------------------------------------------------------------- /_01_introduction/assets/Game-Boy-Advance-SP-Mk1-Blue.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixjones/gba-tutorial/6456e879403bc6c1e5b7f732c76dc4dccbcb1081/_01_introduction/assets/Game-Boy-Advance-SP-Mk1-Blue.jpg -------------------------------------------------------------------------------- /_01_introduction/assets/Game-Boy-FL.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixjones/gba-tutorial/6456e879403bc6c1e5b7f732c76dc4dccbcb1081/_01_introduction/assets/Game-Boy-FL.jpg -------------------------------------------------------------------------------- /_01_introduction/assets/Game-Boy-Micro.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixjones/gba-tutorial/6456e879403bc6c1e5b7f732c76dc4dccbcb1081/_01_introduction/assets/Game-Boy-Micro.jpg -------------------------------------------------------------------------------- /_01_introduction/assets/GameCube-Game-Boy-Player.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixjones/gba-tutorial/6456e879403bc6c1e5b7f732c76dc4dccbcb1081/_01_introduction/assets/GameCube-Game-Boy-Player.jpg -------------------------------------------------------------------------------- /_01_introduction/assets/Gameboy-Advance-SP-Mk2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixjones/gba-tutorial/6456e879403bc6c1e5b7f732c76dc4dccbcb1081/_01_introduction/assets/Gameboy-Advance-SP-Mk2.jpg -------------------------------------------------------------------------------- /_01_introduction/assets/Nintendo-DS-Fat-Blue.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixjones/gba-tutorial/6456e879403bc6c1e5b7f732c76dc4dccbcb1081/_01_introduction/assets/Nintendo-DS-Fat-Blue.jpg -------------------------------------------------------------------------------- /_01_introduction/assets/Nintendo-Game-Boy-Advance-Milky-Blue-FL.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixjones/gba-tutorial/6456e879403bc6c1e5b7f732c76dc4dccbcb1081/_01_introduction/assets/Nintendo-Game-Boy-Advance-Milky-Blue-FL.jpg -------------------------------------------------------------------------------- /_01_introduction/assets/Nintendo-Game-Boy-Color-FL.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixjones/gba-tutorial/6456e879403bc6c1e5b7f732c76dc4dccbcb1081/_01_introduction/assets/Nintendo-Game-Boy-Color-FL.jpg -------------------------------------------------------------------------------- /_01_introduction/assets/QWzuQ54.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixjones/gba-tutorial/6456e879403bc6c1e5b7f732c76dc4dccbcb1081/_01_introduction/assets/QWzuQ54.jpg -------------------------------------------------------------------------------- /_01_introduction/assets/ffta_agb_lcdA.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixjones/gba-tutorial/6456e879403bc6c1e5b7f732c76dc4dccbcb1081/_01_introduction/assets/ffta_agb_lcdA.png -------------------------------------------------------------------------------- /_01_introduction/assets/ffta_agb_lcdB.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixjones/gba-tutorial/6456e879403bc6c1e5b7f732c76dc4dccbcb1081/_01_introduction/assets/ffta_agb_lcdB.png -------------------------------------------------------------------------------- /_01_introduction/assets/ffta_agb_tv.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixjones/gba-tutorial/6456e879403bc6c1e5b7f732c76dc4dccbcb1081/_01_introduction/assets/ffta_agb_tv.png -------------------------------------------------------------------------------- /_01_introduction/assets/ffta_pc_lcdA.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixjones/gba-tutorial/6456e879403bc6c1e5b7f732c76dc4dccbcb1081/_01_introduction/assets/ffta_pc_lcdA.png -------------------------------------------------------------------------------- /_01_introduction/assets/ffta_pc_lcdB.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixjones/gba-tutorial/6456e879403bc6c1e5b7f732c76dc4dccbcb1081/_01_introduction/assets/ffta_pc_lcdB.png -------------------------------------------------------------------------------- /_01_introduction/assets/ffta_pc_tv.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixjones/gba-tutorial/6456e879403bc6c1e5b7f732c76dc4dccbcb1081/_01_introduction/assets/ffta_pc_tv.png -------------------------------------------------------------------------------- /_01_introduction/assets/ffta_title_lcdA.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixjones/gba-tutorial/6456e879403bc6c1e5b7f732c76dc4dccbcb1081/_01_introduction/assets/ffta_title_lcdA.png -------------------------------------------------------------------------------- /_01_introduction/assets/ffta_title_lcdB.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixjones/gba-tutorial/6456e879403bc6c1e5b7f732c76dc4dccbcb1081/_01_introduction/assets/ffta_title_lcdB.png -------------------------------------------------------------------------------- /_01_introduction/assets/ktD5hLc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixjones/gba-tutorial/6456e879403bc6c1e5b7f732c76dc4dccbcb1081/_01_introduction/assets/ktD5hLc.png -------------------------------------------------------------------------------- /_01_introduction/display.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: "Video Hardware" 4 | ordering: 3 5 | --- 6 | 7 | # Display 8 | 9 | ## Geometry 10 | 11 | 240 horizontal pixels, by 160 vertical pixels. 240x160. This was marketed as "wide screen", with a 3:2 aspect ratio. Compared to modern displays, it isn't THAT wide, but compared to the DMG/CGB's 160x144 display (10:9) it is wider. 12 | 13 | On the original GBA models; the display's individual pixels are made up of blue, green, and red components. This is called BGR pixel arrangement. 14 | 15 | Knowing the pixel arrangement lets you do some cool sub-pixel anti-aliasing, but hold your horses on that idea: GBA games can also be played on televisions via the Game Boy Player, and these days you can play GBA games on all sorts of devices on all kinds of displays, so you can't depend on a BGR pixel arrangement. 16 | 17 | > Trivia: Whilst the top screen of the Nintendo DS has BGR pixel arrangement, the bottom screen has RGB pixel arrangement. 18 | 19 | ## Colour Depth 20 | 21 | The LCD displays 15 bits-per-pixel (bpp), 5-bits for blue, 5-bits for green, 5-bits for red. I'll refer to this as BGR555 for short. That makes for 32,768 total colours. Wow! 22 | 23 | In comparison, a typical PC display displays 24-bpp, RGB888 (8-bits for red, green, and blue). 24 | 25 | Whilst the display can only show 15-bpp, the Picture Processor Unit (PPU) handles colours in 16-bits, with the top-most bit unused (or is it unused? More on this later...). 26 | 27 | ## Display Gamma 28 | 29 | Ah, nothing like trying to play Game Boy late at night on the backseat of the family car during a long-drive, with only the amber of the passing street lights there to let you see what the heck is happening in your game. 30 | 31 | We've been spoiled in modern times. 32 | 33 | ### What is "Display Gamma"? 34 | 35 | [We actually perceive colour non-linearly](https://en.wikipedia.org/wiki/Lightness), so if we use a linear colour scale, where 50% grey is exactly 50:50 mix of black and white, our eyes will perceive that there are more light shades, than dark shades. 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 48 | 49 | 50 | 55 |
 0123456789X
sRGB 44 | 45 | 46 | 47 |
Linear 51 | 52 | 53 | 54 |
56 | 57 | You're likely viewing this document on an sRGB display, so the sRGB column should look like a smooth gradient (if it doesn't, perhaps calibrate your display). 58 | The bottom row is the same gradient, converted to linear colour space (where 50% is 50:50 grey). I have no way of proving this, because we're all on sRGB displays (plus, sRGB is the standard for web rendering), but trust me it is converted to linear. Notice how this gradient brightens quite rapidly in contrast. 59 | 60 | [sRGB is a colour standard](https://en.wikipedia.org/wiki/SRGB) for displays on PC monitors that has become ubiquitous. sRGB assumes a gamma of 2.2, which means (in very rough terms) all linear colour is raised to a power of 2.2 to produce the perception of linear colour on our displays. 61 | 62 | > Trivia: Gamma is the third letter of the Greek alphabet, and its lower-case character is: γ which is probably why the GBA register for brightness is named "Blend Y" with the Latin letter "Y" resembling gamma. 63 | 64 | ### What is the GBA's display "Gamma"? 65 | 66 | There's a cute way to figure out a display's gamma: use a dithering of pure black and white pixels to create a gradient, this dithering results in a perceptual linear gradient. If this is displayed along side a real gradient you can sort of estimate the distance between the two 50% greys of both gradients. If they're both bang in the middle (unlikely) then you've got a gamma of 1. 67 | 68 | [Damian "PinoBatch" Yerrick](https://twitter.com/PinoBatch) estimates the GBA's gamma to be [somewhere between 3 and 4](https://pineight.com/gba/#static). What does that mean? It means the GBA's display is freaking DARK. 69 | [teryor](https://www.blogger.com/profile/09825626907766471207) also conducted [their own experiments](http://codewitchgamedev.blogspot.com/2015/08/emulating-gbas-display-with-gamma.html) and estimates the gamma for the individual RGB channels to be 4.0, 3.0, and 1.4 (so blue should be a bit more perceivable). 70 | 71 | |Photograph of an AGB-001 showing a Pokemon center from Pokemon Sapphire|Tilemap of a Pokemon center from Pokemon Sapphire, with the right-side adjusted for AGB-001 gamma| 72 | |---|---| 73 | |Photo by [teryor](https://www.blogger.com/profile/09825626907766471207)|Tilemap adjustment by [teryor](https://www.blogger.com/profile/09825626907766471207)| 74 | 75 | How on earth did we ever see ANYTHING on this device? Well, as a child you didn't really care because it's still a GBA, the most powerful hand-held games console (at the time). 76 | 77 | Also we all had these weird over-head light accessories that shone an annoying blob of light right at the middle of the screen, so you had to constantly angle the device as you played to see what you're doing. 78 | 79 | The AGS-101 (backlit SP), Game Boy Player, Micro, and onwards all assume a display closer to that of an LCD TV (which we can assume has a gamma of 2.2, an sRGB PC display). 80 | 81 | ### But wait, there's more! 82 | 83 | On the History page I mentioned that the frontlit AGS-001 (first model of SP) has a "slightly bluish hue" to its light? Well, now not only is the screen is more visible (gamma is still a little dark), but it's also a bit blue. 84 | 85 | ## Optimising for various displays 86 | 87 | Final Fantasy Tactics Advance provides 3 colour palettes named "LCD A", "LCD B", and "TV". Each of these palettes attempt to adjust for the various GBA displays. 88 | 89 | Below I have the game running in the [mGBA emulator](https://mgba.io/) showing each display palette and comparing against mGBA with its built-in AGB shader (designed to mimic the colour profile of the AGB, but luckily not the darkness). 90 | 91 | ||mGBA|AGB shader| 92 | |---|---|---| 93 | |LCD A
(AGB-001)|Final Fantasy Tactics Advance on mGBA with LCD A|Final Fantasy Tactics Advance on mGBA with LCD A| 94 | |LCD B
(AGS-001)|Final Fantasy Tactics Advance on mGBA with LCD B|Final Fantasy Tactics Advance on mGBA with LCD B| 95 | |TV
(DOL-017)|Final Fantasy Tactics Advance on mGBA with TV|Final Fantasy Tactics Advance on mGBA with TV| 96 | 97 | It is very likely that the lower-left is the artist-intended vision for the game, with the sprites and artwork possibly calibrated on an sRGB PC display monitor. 98 | 99 | The top-left is likely how most people are playing the game in emulator today, as it is the default palette and most people typically don't think to explore the options screen of most video games. See how yellow the characters are in the top left versus the bottom left. 100 | 101 | Interestingly, "LCD B" on the right looks similar to "TV" on the left. 102 | 103 | Calculating the colour difference between "LCD A" and "LCD B" reveals that it's mostly a contrast change ("LCD B" has darker outlines), but I did notice that for the title screen it reduces the strength of the blue hues, leading me to believe "LCD B" is intended for the rather blue-ish, slightly low-contrast, AGS-001 front-light. 104 | 105 | |Title screen LCD A|Title screen LCD B| 106 | |---|---| 107 | |Final Fantasy Tactics Advance's title screen with LCD A|Final Fantasy Tactics Advance's title screen with LCD B| 108 | -------------------------------------------------------------------------------- /_01_introduction/history.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: "A Brief History" 4 | ordering: 1 5 | --- 6 | 7 | # The Game Boy Advance 8 | 9 | It's Game Boy **Advance**, **not Advance*d*! Also note that "Game Boy" is two words. It's not Gameboy, Game-Boy or GameBoy: It's Game Boy (notice the space). Game Boy Advance. 10 | 11 | ## History 12 | 13 | Chances are; you're here because you know about the Game Boy, and specifically the Game Boy Advance. Even so, there's some history that might be good to know if you're looking to start GBA development. 14 | 15 | ### Game Boy / Game Boy Color 16 | 17 | These are the two iterations of classic Game Boy. These machines both use a custom made 8-bit "LR35902" CPU from Sharp that runs at \~4.19 MHz in Game Boy mode, and \~8.39 MHz in Game Boy Color mode. The CPU instruction set is a blend of 8080 and Z80. 18 | 19 | Now this is very important: The Game Boy Advance is entirely different to both of these. This tutorial will **NOT** (and I repeat: **NOT**) help you learn how to create Game Boy or Game Boy Color games. 20 | 21 | If these consoles are mentioned, they will be referred to as "DMG" for Game Boy, and "CGB" for Game Boy Color. These stand for "Dot Matrix Game" and "Color Game Boy", the codenames for both of these machines. 22 | 23 | |Game Boy|Game Boy Color| 24 | |---|---| 25 | |Photo of DMG|Photo of CGB| 26 | |Photo of DMG by [Evan Amos](https://commons.wikimedia.org/wiki/User:Evan-Amos)|Photo of CGB by [Evan Amos](https://commons.wikimedia.org/wiki/User:Evan-Amos)| 27 | 28 | ### Game Boy Advance 29 | 30 | Released in 2001, the Game Boy Advance is the successor to the Game Boy Color. It features a wider screen (240x160 pixels), two shoulder buttons (L and R) and a *completely* different architecture to past Game Boys. Original Game Boy hardware does exist inside the Game Boy Advance for backwards compatibility, but it is completely unavailable when operating in Game Boy Advance mode. 31 | 32 | There are several members of the Game Boy Advance family: 33 | 34 | |Model|Model ID|Code name|Release date|Notes|Photo| 35 | |---|---|---|---|---|---| 36 | |Game Boy Advance|AGB-001|Advance Game Boy|March 21, 2001|Original model (No light, reflective LCD)|Photo of AGB-001| 37 | |Game Boy Advance SP|AGS-001|Game Boy Advance Special|February 14, 2003|Frontlight, reflective LCD (with a slightly bluish hue)|Photo of AGS-001| 38 | |Game Boy Player|DOL-017|-|March 21, 2003|An accessory that lets you play Game Boy games on a TV via a Game Cube|Photo of DOL-017| 39 | |Game Boy Advance SP
(Now with a BRIGHTER backlit screen!)|AGS-101|-|September 2005|Backlight LCD (and it looks gorgeous)|Photo of AGS-101| 40 | |Game Boy micro|OXY|Oxy|September 13, 2005|No DMG/CGB backwards compatibility|Photo of OXY| 41 | 42 | (Photos by [Evan Amos](https://commons.wikimedia.org/wiki/User:Evan-Amos)) 43 | 44 | All these models of Game Boy Advance will be referred to as the Game Boy Advance, or GBA for short. Model IDs will be used when mentioning information specific to particular models. 45 | 46 | > Non-trivia: I seem to remember reading in a magazine prior to the SP's release that it stood for "Special Project" and was intended to be a limited run design. I can find zero sources on the internet regarding this, so probably my dumb kid brain messing up the rememberings. 47 | 48 | ### Nintendo DS 49 | 50 | Worth mentioning because there is GBA backwards compatibility (but no DMG/CGB) and there are some things to note. 51 | 52 | Released in 2004, the DS stands for "Dual Screen". There are two models of interest to us: Original Nintendo DS (codename Nitro, model ID NTR), and the 2006 revision: DS Lite (model ID USG). 53 | 54 | |Photo of NTR| 55 | |---| 56 | |Photo of NTR by [Evan Amos](https://commons.wikimedia.org/wiki/User:Evan-Amos)| 57 | 58 | Later DS models dropped GBA support, but the GBA hardware secretly lives inside them, and is even used for the GBA virtual console of the 3DS (the DS' successor, if you haven't heard of it). 59 | 60 | > Trivia: [open_agb_firm](https://github.com/profi200/open_agb_firm) is a project that unlocks the GBA hardware for the 3DS, allowing native play of GBA games via dumped ROMs. 61 | -------------------------------------------------------------------------------- /_01_introduction/sound.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: "Audio Hardware" 4 | ordering: 4 5 | --- 6 | 7 | I have found that many people approaching the GBA for the first time ask "What is its sound chip like?". Perhaps if it had a sound-chip, I'd be able to give an answer. 8 | -------------------------------------------------------------------------------- /_02_setup/assets/mgba-0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixjones/gba-tutorial/6456e879403bc6c1e5b7f732c76dc4dccbcb1081/_02_setup/assets/mgba-0.png -------------------------------------------------------------------------------- /_02_setup/assets/path-0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixjones/gba-tutorial/6456e879403bc6c1e5b7f732c76dc4dccbcb1081/_02_setup/assets/path-0.png -------------------------------------------------------------------------------- /_02_setup/assets/path-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixjones/gba-tutorial/6456e879403bc6c1e5b7f732c76dc4dccbcb1081/_02_setup/assets/path-1.png -------------------------------------------------------------------------------- /_02_setup/assets/path-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixjones/gba-tutorial/6456e879403bc6c1e5b7f732c76dc4dccbcb1081/_02_setup/assets/path-2.png -------------------------------------------------------------------------------- /_02_setup/assets/path-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixjones/gba-tutorial/6456e879403bc6c1e5b7f732c76dc4dccbcb1081/_02_setup/assets/path-3.png -------------------------------------------------------------------------------- /_02_setup/assets/path-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixjones/gba-tutorial/6456e879403bc6c1e5b7f732c76dc4dccbcb1081/_02_setup/assets/path-4.png -------------------------------------------------------------------------------- /_02_setup/assets/vscode-0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixjones/gba-tutorial/6456e879403bc6c1e5b7f732c76dc4dccbcb1081/_02_setup/assets/vscode-0.png -------------------------------------------------------------------------------- /_02_setup/assets/vscode-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixjones/gba-tutorial/6456e879403bc6c1e5b7f732c76dc4dccbcb1081/_02_setup/assets/vscode-1.png -------------------------------------------------------------------------------- /_02_setup/assets/vscode-10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixjones/gba-tutorial/6456e879403bc6c1e5b7f732c76dc4dccbcb1081/_02_setup/assets/vscode-10.png -------------------------------------------------------------------------------- /_02_setup/assets/vscode-11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixjones/gba-tutorial/6456e879403bc6c1e5b7f732c76dc4dccbcb1081/_02_setup/assets/vscode-11.png -------------------------------------------------------------------------------- /_02_setup/assets/vscode-12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixjones/gba-tutorial/6456e879403bc6c1e5b7f732c76dc4dccbcb1081/_02_setup/assets/vscode-12.png -------------------------------------------------------------------------------- /_02_setup/assets/vscode-13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixjones/gba-tutorial/6456e879403bc6c1e5b7f732c76dc4dccbcb1081/_02_setup/assets/vscode-13.png -------------------------------------------------------------------------------- /_02_setup/assets/vscode-14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixjones/gba-tutorial/6456e879403bc6c1e5b7f732c76dc4dccbcb1081/_02_setup/assets/vscode-14.png -------------------------------------------------------------------------------- /_02_setup/assets/vscode-15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixjones/gba-tutorial/6456e879403bc6c1e5b7f732c76dc4dccbcb1081/_02_setup/assets/vscode-15.png -------------------------------------------------------------------------------- /_02_setup/assets/vscode-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixjones/gba-tutorial/6456e879403bc6c1e5b7f732c76dc4dccbcb1081/_02_setup/assets/vscode-16.png -------------------------------------------------------------------------------- /_02_setup/assets/vscode-17.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixjones/gba-tutorial/6456e879403bc6c1e5b7f732c76dc4dccbcb1081/_02_setup/assets/vscode-17.png -------------------------------------------------------------------------------- /_02_setup/assets/vscode-18.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixjones/gba-tutorial/6456e879403bc6c1e5b7f732c76dc4dccbcb1081/_02_setup/assets/vscode-18.png -------------------------------------------------------------------------------- /_02_setup/assets/vscode-19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixjones/gba-tutorial/6456e879403bc6c1e5b7f732c76dc4dccbcb1081/_02_setup/assets/vscode-19.png -------------------------------------------------------------------------------- /_02_setup/assets/vscode-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixjones/gba-tutorial/6456e879403bc6c1e5b7f732c76dc4dccbcb1081/_02_setup/assets/vscode-2.png -------------------------------------------------------------------------------- /_02_setup/assets/vscode-20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixjones/gba-tutorial/6456e879403bc6c1e5b7f732c76dc4dccbcb1081/_02_setup/assets/vscode-20.png -------------------------------------------------------------------------------- /_02_setup/assets/vscode-21.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixjones/gba-tutorial/6456e879403bc6c1e5b7f732c76dc4dccbcb1081/_02_setup/assets/vscode-21.png -------------------------------------------------------------------------------- /_02_setup/assets/vscode-22.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixjones/gba-tutorial/6456e879403bc6c1e5b7f732c76dc4dccbcb1081/_02_setup/assets/vscode-22.png -------------------------------------------------------------------------------- /_02_setup/assets/vscode-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixjones/gba-tutorial/6456e879403bc6c1e5b7f732c76dc4dccbcb1081/_02_setup/assets/vscode-3.png -------------------------------------------------------------------------------- /_02_setup/assets/vscode-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixjones/gba-tutorial/6456e879403bc6c1e5b7f732c76dc4dccbcb1081/_02_setup/assets/vscode-4.png -------------------------------------------------------------------------------- /_02_setup/assets/vscode-5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixjones/gba-tutorial/6456e879403bc6c1e5b7f732c76dc4dccbcb1081/_02_setup/assets/vscode-5.png -------------------------------------------------------------------------------- /_02_setup/assets/vscode-6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixjones/gba-tutorial/6456e879403bc6c1e5b7f732c76dc4dccbcb1081/_02_setup/assets/vscode-6.png -------------------------------------------------------------------------------- /_02_setup/assets/vscode-7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixjones/gba-tutorial/6456e879403bc6c1e5b7f732c76dc4dccbcb1081/_02_setup/assets/vscode-7.png -------------------------------------------------------------------------------- /_02_setup/assets/vscode-8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixjones/gba-tutorial/6456e879403bc6c1e5b7f732c76dc4dccbcb1081/_02_setup/assets/vscode-8.png -------------------------------------------------------------------------------- /_02_setup/assets/vscode-9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felixjones/gba-tutorial/6456e879403bc6c1e5b7f732c76dc4dccbcb1081/_02_setup/assets/vscode-9.png -------------------------------------------------------------------------------- /_02_setup/debugging.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: "Debugging with VSCode" 4 | ordering: 2 5 | --- 6 | 7 | # Debugging with GDB 8 | 9 | ## Launch configuration 10 | 11 | Create a new file called "launch.json" in the `.vscode` directory. VSCode should recognise this file and display an *Add Configuration* button. 12 | 13 | VSCode with launch.json selected and a red arrow pointing at Add Configuration 14 |   15 | 16 | Choose the `C/C++: (gdb) Launch` option to generate the JSON for us to fill in. 17 | 18 | VSCode with a red arrow pointing at C/C++: (gdb) Launch 19 |   20 | 21 | We should now have something like the below: 22 | 23 | ```json 24 | { 25 | "configurations": [ 26 | { 27 | "name": "(gdb) Launch", 28 | "type": "cppdbg", 29 | "request": "launch", 30 | "program": "enter program name, for example ${workspaceFolder}/a.exe", 31 | "args": [], 32 | "stopAtEntry": false, 33 | "cwd": "${fileDirname}", 34 | "environment": [], 35 | "externalConsole": false, 36 | "MIMode": "gdb", 37 | "miDebuggerPath": "/path/to/gdb", 38 | "setupCommands": [ 39 | { 40 | "description": "Enable pretty-printing for gdb", 41 | "text": "-enable-pretty-printing", 42 | "ignoreFailures": true 43 | }, 44 | { 45 | "description": "Set Disassembly Flavor to Intel", 46 | "text": "-gdb-set disassembly-flavor intel", 47 | "ignoreFailures": true 48 | } 49 | ] 50 | } 51 | 52 | ] 53 | } 54 | ``` 55 | 56 | ### Launch.json Target Architecture 57 | 58 | By default, VSCode assumes you are going to be debugging the architecture that you're developing from. 59 | 60 | Add the field "targetArchitecture" with the value "arm" below the "request" field to inform gdb that we are debugging ARM: 61 | ```json 62 | "request": "launch", 63 | "targetArchitecture": "arm", 64 | ``` 65 | 66 | ### Launch.json Program 67 | 68 | First, change the program field to point to our GBA ELF file. 69 | 70 | VSCode CMake tools [comes with a few commands](https://vector-of-bool.github.io/docs/vscode-cmake-tools/settings.html) that makes writing these files a bit easier. 71 | 72 | We can use "${command:cmake.buildDirectory}" to get the build directory of our current CMake configuration. Inside this directory is where our ELF file is built. 73 | 74 | My ELF file is called "gba-game.elf", so my "program" field should be: 75 | ```json 76 | "program": "${command:cmake.buildDirectory}/gba-game.elf", 77 | ``` 78 | 79 | ### Current working directory 80 | 81 | This is the working directory of the gdb server (more on this in a bit). Set this to just the build directory (you'll see why soon): 82 | ```json 83 | "cwd": "${command:cmake.buildDirectory}", 84 | ``` 85 | 86 | ### Debugging server address 87 | 88 | We'll be using mGBA's fantastic built-in gdb-server for debugging. By default, this listens on port `2345`. Because we'll be running mGBA locally, we'll address it with `localhost`. 89 | 90 | Add a field after "MIMode" called "miDebuggerServerAddress" and set its value to "localhost:2345": 91 | ```json 92 | "MIMode": "gdb", 93 | "miDebuggerServerAddress": "localhost:2345", 94 | ``` 95 | MIMode is the type of debugger we'll be using. mGBA has a gdb-server, so we'll be using gdb. 96 | 97 | ### mGBA debugging server 98 | 99 | Where our debugger is and how we connect to it will depend on our platform. The "miDebuggerPath" and the "setupCommands" will vary, so delete these fields completely: 100 | ```json 101 | "miDebuggerPath": "/path/to/gdb", 102 | "setupCommands": [ 103 | { 104 | "description": "Enable pretty-printing for gdb", 105 | "text": "-enable-pretty-printing", 106 | "ignoreFailures": true 107 | }, 108 | { 109 | "description": "Set Disassembly Flavor to Intel", 110 | "text": "-gdb-set disassembly-flavor intel", 111 | "ignoreFailures": true 112 | } 113 | ] 114 | ``` 115 | And let's replace these with entries for Windows, Linux, and macOS: 116 | ```json 117 | "windows": { 118 | "miDebuggerPath": "", 119 | "setupCommands": [] 120 | }, 121 | "linux": { 122 | "miDebuggerPath": "", 123 | "setupCommands": [] 124 | }, 125 | "osx": { 126 | "miDebuggerPath": "", 127 | "setupCommands": [] 128 | } 129 | ``` 130 | 131 | #### Debugger path 132 | 133 | gba-toolchain by default will download and install the ARM GNU toolchain to a convenient shared directory. That is where our ARM gdb client is, so we need set the "miDebuggerPath" fields to the "arm-none-eabi-gdb" path depending on our operating system. 134 | 135 | |OS|Where|VSCode variable| 136 | |-|-|-| 137 | |Windows|%LOCALAPPDATA%|${env:LOCALAPPDATA}| 138 | |Linux|Home|${env:HOME}| 139 | |macOS|Local user share|/usr/local/share/| 140 | 141 | So fill in the "miDebuggerPath" fields with the paths: 142 | ```json 143 | "windows": { 144 | "miDebuggerPath": "${env:LOCALAPPDATA}/arm-gnu-toolchain/bin/arm-none-eabi-gdb.exe", 145 | "setupCommands": [] 146 | }, 147 | "linux": { 148 | "miDebuggerPath": "~/arm-gnu-toolchain/bin/arm-none-eabi-gdb", 149 | "setupCommands": [] 150 | }, 151 | "osx": { 152 | "miDebuggerPath": "/usr/local/share/arm-gnu-toolchain/bin/arm-none-eabi-gdb", 153 | "setupCommands": [] 154 | } 155 | ``` 156 | If you configured gba-toolchain to instead use an ARM GNU toolchain in another directory then you will need to adjust these fields. 157 | 158 | #### mGBA setup commands 159 | 160 | We'll add into "setupCommands" the command to launch mGBA's gdb-server and our GBA program. 161 | 162 | Due to a quirk in how mGBA runs and how VSCode waits for gdb-servers to connect, we have to launch mGBA as its own process so there's no deadlock between it and VSCode. 163 | 164 | On Windows this can be done with the `start /b ""` command. On Linux and macOS you need only to end your shell command with the ampersand symbol `&`, however on macOS we can open the mGBA app in its own process with the `open -a` command. 165 | 166 | mGBA uses the `-g` option to start its gdb-server, so we need to include that. 167 | 168 | Here's my setup commands that I use on Windows, Linux, and macOS: 169 | 170 | ##### Windows 171 | 172 | On my Windows machine, mGBA.exe is located at "C:/Program Files/mGBA/mGBA.exe". 173 | 174 | ```json 175 | "windows": { 176 | "miDebuggerPath": "${env:LOCALAPPDATA}/arm-gnu-toolchain/bin/arm-none-eabi-gdb.exe", 177 | "setupCommands": [ 178 | { 179 | "text": "shell start /b \"\" \"C:/Program Files/mGBA/mGBA.exe\" -g \"${command:cmake.buildDirectory}/gba-game.elf\"" 180 | } 181 | ] 182 | }, 183 | ``` 184 | 185 | ##### Linux 186 | 187 | On my Linux machine, mgba-qt is located at "/usr/local/bin/mgba-qt". 188 | 189 | ```json 190 | "linux": { 191 | "miDebuggerPath": "~/arm-gnu-toolchain/bin/arm-none-eabi-gdb", 192 | "setupCommands": [ 193 | { 194 | "text": "shell \"/usr/local/bin/mgba-qt\" -g \"${command:cmake.buildDirectory}/gba-game.elf\" &" 195 | } 196 | ] 197 | }, 198 | ``` 199 | 200 | ##### macOS 201 | 202 | On my macOS machine, mGBA is located at "/Applications/mGBA.app", which can be opened with the `open -a mGBA` command. 203 | 204 | ```json 205 | "osx": { 206 | "miDebuggerPath": "/usr/local/share/arm-gnu-toolchain/bin/arm-none-eabi-gdb", 207 | "setupCommands": [ 208 | { 209 | "text": "shell open -a mGBA --args -g \"${command:cmake.buildDirectory}/gba-game.elf\"" 210 | } 211 | ] 212 | } 213 | ``` 214 | 215 | ## The final launch.json 216 | 217 | This is what my launch.json looks like after setting it up: 218 | 219 | ```json 220 | { 221 | "configurations": [ 222 | { 223 | "name": "(gdb) Launch", 224 | "type": "cppdbg", 225 | "request": "launch", 226 | "targetArchitecture": "arm", 227 | "program": "${command:cmake.buildDirectory}/gba-game.elf", 228 | "args": [], 229 | "stopAtEntry": false, 230 | "cwd": "${command:cmake.buildDirectory}", 231 | "environment": [], 232 | "externalConsole": false, 233 | "MIMode": "gdb", 234 | "miDebuggerServerAddress": "localhost:2345", 235 | "windows": { 236 | "miDebuggerPath": "${env:LOCALAPPDATA}/arm-gnu-toolchain/bin/arm-none-eabi-gdb.exe", 237 | "setupCommands": [ 238 | { 239 | "text": "shell start /b \"\" \"C:/Program Files/mGBA/mGBA.exe\" -g \"${command:cmake.buildDirectory}/gba-game.elf\"" 240 | } 241 | ] 242 | }, 243 | "linux": { 244 | "miDebuggerPath": "~/arm-gnu-toolchain/bin/arm-none-eabi-gdb", 245 | "setupCommands": [ 246 | { 247 | "text": "shell \"/usr/local/bin/mgba-qt\" -g \"${command:cmake.buildDirectory}/gba-game.elf\" &" 248 | } 249 | ] 250 | }, 251 | "osx": { 252 | "miDebuggerPath": "/usr/local/share/arm-gnu-toolchain/bin/arm-none-eabi-gdb", 253 | "setupCommands": [ 254 | { 255 | "text": "shell open -a mGBA --args -g \"${command:cmake.buildDirectory}/gba-game.elf\"" 256 | } 257 | ] 258 | } 259 | } 260 | 261 | ] 262 | } 263 | ``` 264 | 265 | Of course, if you don't need to worry about particular operating systems you can remove their entries entirely, but I have all 3 here just for your reference. 266 | 267 | ## Set a breakpoint 268 | 269 | It's time to debug! 270 | 271 | In our main.c, click in the margin to the left of line 7 to set a breakpoint. 272 | 273 | VSCode main.c with a breakpoint set 274 |   275 | 276 | If everything has been set up correctly, we should now be able to use Run -> Start Debugging: 277 | 278 | VSCode with the Start Debugging option 279 |   280 | 281 | And once mGBA launches, our breakpoint should be hit and VSCode will enter debugging mode: 282 | 283 | VSCode with the Start Debugging option 284 |   285 | 286 | Notice how I expanded the registers view to see the CPU registers. 287 | 288 | For information on using the VSCode debugger take a look at: https://code.visualstudio.com/docs/editor/debugging 289 | 290 | You can also use the debugging console to send gdb commands: 291 | 292 | VSCode with the Start Debugging option 293 |   294 | 295 | mGBA's memory viewer, register viewer, etc, are all available also. 296 | -------------------------------------------------------------------------------- /_02_setup/real-gba.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: "Testing on a real GBA" 4 | ordering: 3 5 | --- 6 | 7 | Notice that so far we've just been dealing with ELF files. ELF is great for debugging, but a real GBA needs raw-binary to execute. 8 | 9 | # Creating a GBA binary 10 | 11 | ## objcopy 12 | 13 | We turn our ELF into a binary by copying the various binary sections described by the ELF into a binary object. The GNU program for this is called "objcopy". 14 | 15 | Let's go back to our CMakeLists.txt file: 16 | 17 | ```cmake 18 | cmake_minimum_required(VERSION 3.18) 19 | 20 | project("My GBA Project" C) 21 | 22 | add_executable(gba-game main.c) 23 | set_target_properties(gba-game PROPERTIES SUFFIX ".elf") 24 | 25 | gba_add_library_subdirectory(rom) 26 | 27 | target_link_libraries(gba-game PRIVATE rom) 28 | ``` 29 | 30 | gba-toolchain provides the CMake function `gba_target_objcopy` for running objcopy on our target. 31 | 32 | So let's add this to our CMakeLists.txt: 33 | ```cmake 34 | gba_target_objcopy(gba-game) 35 | ``` 36 | 37 | Which should now look like: 38 | 39 | ```cmake 40 | cmake_minimum_required(VERSION 3.18) 41 | 42 | project("My GBA Project" C) 43 | 44 | add_executable(gba-game main.c) 45 | set_target_properties(gba-game PROPERTIES SUFFIX ".elf") 46 | 47 | gba_add_library_subdirectory(rom) 48 | 49 | target_link_libraries(gba-game PRIVATE rom) 50 | 51 | gba_target_objcopy(gba-game) 52 | ``` 53 | 54 | Now when we build we should see in the build output "Copying object gba-game.gba" 55 | 56 | VSCode showing the build output 57 |   58 | 59 | And in our build folder is "gba-game.gba". Feel free to open this in mGBA, the output should be the same as the ELF program. 60 | 61 | ## Fixing the header 62 | 63 | If at this point you tried to run this binary on actual hardware you'll realise it doesn't work (well, unless your Flashcart skips the BIOS). 64 | 65 | This is because the GBA checks the header of the ROM to validate it's a GBA binary before execution begins. This is part of Nintendo's attempt at preventing the production of unlicensed GBA ROMs[.](https://en.wikipedia.org/wiki/Sega_v._Accolade) 66 | 67 | gba-toolchain uses a community made tool called "gbafix" to fix ROM headers. But first, gba-toolchain needs to compile gbafix. 68 | 69 | ### Install host compiler 70 | 71 | gba-toolchain needs a host compiler to compile its tools. 72 | 73 | Follow the VSCode guide on checking if you have a host compiler installed: [code.visualstudio.com/docs/languages/cpp#_install-a-compiler](https://code.visualstudio.com/docs/languages/cpp#_install-a-compiler) 74 | 75 | If you don't, then install one. That page provides MinGW-x64 as an example on Windows. On Linux and macOS it is a bit easier: 76 | 77 | [Search for how to install GCC for your particular Linux distribution](https://www.google.com/search?q=how+to+install+GCC+on+Linux). 78 | 79 | [Search for how to install Apple Command Line Tools](https://www.google.com/search?q=how+to+install+Apple+Command+Line+Tools). 80 | 81 | Visual Studio on Windows works, but make sure you've installed the complete C/C++ development environment. 82 | 83 | If you've done C/C++ development already, chances are you have a host complier and this should "just work". 84 | 85 | ### Running gbafix 86 | 87 | gba-toolchain's `gba_target_objcopy` CMake function takes the parameter: `FIX_HEADER`. Once that argument is used, gba-toolchain will attempt to find gbafix, if it fails then it will download it and attempt to compile it. If that fails, then please re-read the previous section on installing a host compiler (you may need to delete your CMakeCache.txt file!). 88 | 89 | Our CMakeLists.txt should now look like this: 90 | 91 | ```cmake 92 | cmake_minimum_required(VERSION 3.18) 93 | 94 | project("My GBA Project" C) 95 | 96 | add_executable(gba-game main.c) 97 | set_target_properties(gba-game PROPERTIES SUFFIX ".elf") 98 | 99 | gba_add_library_subdirectory(rom) 100 | 101 | target_link_libraries(gba-game PRIVATE rom) 102 | 103 | gba_target_objcopy(gba-game FIX_HEADER) 104 | ``` 105 | 106 | Delete your previous ELF and GBA ROM, and rebuild. You should see a confirmation "ROM Fixed!" in the output: 107 | 108 | VSCode showing the build output with ROM Fixed! printed 109 |   110 | 111 | Now you can take your ROM and try it out on a real GBA console. 112 | 113 | ## Additional gbafix options 114 | 115 | The ROM header has the following additional fields: 116 | 117 | |Field|Usage|gba-toolchain parameter| 118 | |-|-|-| 119 | |Title|12 character ASCII title of your game|TITLE "My Game"| 120 | |Game Code|4 character game code in UTTD format|GAME_CODE UTTD1| 121 | |Maker Code|2 character ASCII code representing your studio|MAKER_CODE ":)"| 122 | |Version|Integer ROM version from 0 to 255|VERSION 100| 123 | 124 | 1 UTTD format stands for Unique-code, short Title, and Desination/language. 125 | 126 | Unique code probably had some special meaning. Short title is a two character title of your game's name (So Pac-Man would probably be "pm"), and destination/language is a single character describing the region or language of your game. P for PAL, E for English, J for Japanese, F for French, etc. 127 | 128 | Here's an example of using this with gba-toolchain in CMakeLists.txt: 129 | 130 | ```cmake 131 | gba_target_objcopy(gba-game FIX_HEADER 132 | TITLE "My Game" 133 | GAME_CODE 2MGE # 2 for SRAM (see below), MG for My Game, E for English 134 | MAKE_CODE GT # GT for "Gba Tutorial" 135 | VERSION 1 # Or perhaps we should start from version 0? 136 | ) 137 | ``` 138 | 139 | ### UTTD and the Everdrive X5 Flashcart 140 | 141 | Version 1.13 of the Everdrive X5 OS uses an ASCII number (1 to 4) as the unique code for an easy way to identify save-type: 142 | 143 | 1. EEPROM 144 | 2. SRAM 145 | 3. FLASH-64 146 | 4. FLASH-128 147 | 148 | For friendliness towards the X5, I recommend using this if possible! 149 | -------------------------------------------------------------------------------- /_02_setup/toolchain.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: "Setup with VSCode" 4 | ordering: 1 5 | --- 6 | 7 | # gba-toolchain 8 | 9 | This setup tutorial will cover compiling a GBA ROM with the [gba-toolchain](https://github.com/felixjones/gba-toolchain). What is the gba-toolchain? Well, it's a CMake-based toolchain written by yours truly. 10 | 11 | You can download the repository from [github.com/felixjones/gba-toolchain](https://github.com/felixjones/gba-toolchain), or you can just download the toolchain script from [github.com/felixjones/gba-toolchain/3.0/arm-gba-toolchain.cmake](https://raw.githubusercontent.com/felixjones/gba-toolchain/3.0/arm-gba-toolchain.cmake). 12 | 13 | Extract the repo (or save the script) to a location that you can easily reference later. 14 | On Windows a handy location could be your user directory at `%userprofile%`. On Linux or Mac, perhaps your `home` directory. 15 | 16 | ## CMake 17 | 18 | CMake has a pretty handy mechanism for cross-compiling called "CMake toolchains". gba-toolchain is a CMake toolchain, but one that sets up everything you need for GBA development, including tools and libraries. 19 | 20 | gba-toolchain requires CMake 3.18, so go ahead and [download CMake](https://cmake.org/download) if you're following along. 21 | 22 | ## Ninja (Windows) 23 | 24 | [Ninja](https://ninja-build.org/) is an alternative to the classic Make build system. We will use this as our CMake generator target on Windows. 25 | 26 | Download the latest build of Ninja for win from [github.com/ninja-build/ninja/releases](https://github.com/ninja-build/ninja/releases) and extract it to a sensible location that we'll add as a PATH variable. I recommend making a folder called "ninja" in your homepath `%HOMEPATH%`, so the `ninja.exe` file should be located at `%HOMEPATH%\ninja\ninja.exe`. 27 | 28 | To add a Windows path variable open the "Edit the system environment variables" shortcut from the start menu: 29 | 30 | Windows Start menu showing the Edit the system environment variables shortcut  31 | 32 | Then click the `Environment Variables...` button: 33 | 34 | The System Properties window with the Environment Variables button highlighted  35 | 36 | In the User variables at the top select Path then click Edit: 37 | 38 | The Environment Variables window with the upper Path option selected  39 | 40 | Then from here, click the New button to create a new field. If you copied Ninja to `%HOMEPATH%\ninja\ninja.exe` then you can type "%HOMEPATH%\\ninja\\" in the text entry and hit ok, otherwise you can click Browse and locate the directory manually. 41 | 42 | The Edit environment variable window with a new Path field  43 | 44 | To test that Ninja is working open Command Prompt and type `ninja --version` 45 | 46 | Command Prompt showing Ninja --version  47 | 48 | ## Visual Studio Code 49 | 50 | Modern IDEs tend to have good support for CMake based projects. VSCode is one of them (via the CMake plugin). Like CMake, it's cross-platform. 51 | 52 | [Download VSCode here](https://code.visualstudio.com/). Oh and important note: **VSCode is not Visual Studio**. Cross-compiled CMake projects can work with Visual Studio, but it's both Windows-only and isn't a common use case of Visual Studio (so its support can be buggy). 53 | 54 | Once you've got VSCode installed, click the extensions button so we can download everything needed for C/C++ devel opment. 55 | 56 | Start screen of VSCode with an arrowing pointing at the extensions button 57 | 58 | ### C/C++ Development Extension 59 | 60 | This is a Microsoft extension for VSCode that adds language support for C/C++ to VSCode, including debugging! 61 | 62 | This also comes with CMake support (handy!). 63 | 64 | Start screen of VSCode with an arrowing pointing at the extensions button 65 | 66 | Searching "C++" in the extensions window should get you to the Microsoft C/C++ extension. 67 | 68 | Click *Install*. 69 | 70 | ## Creating a GBA project 71 | 72 | Make a project folder somewhere (can be anywhere) and give it a name like `My GBA Project` or something of that sort. I put my project folder on my Desktop. 73 | 74 | Back in VSCode, go to File -> Open Folder... and find your project folder. 75 | 76 | VSCode with the File menu open and an arrow pointing at Open Folder 77 | 78 | ### Creating a source file 79 | 80 | We'll start by making a C program. Create a new file in our project and name it `main.c`. 81 | 82 | VSCode with the File menu open and an arrow pointing at New File 83 |   84 | 85 | With an empty file, VSCode usually asks you to select a language. If it does, go ahead and select `C`, as we'll be starting off with a C language project. 86 | 87 | VSCode with an arrow pointing at the Select a language shortcut in the text editor 88 |   89 | VSCode with the language selection open and a red arrow pointing at C 90 |   91 | 92 | VSCode may recommend some extensions for a better C development experience. Feel free to install those. 93 | 94 | VSCode dialogue recommending an install of extensions for C 95 |   96 | 97 | Let's paste in a classic demo from the original Tonc1 tutorial. 98 | 99 | ```c 100 | // First demo. You are not expected to understand it 101 | // (don't spend too much time trying and read on). 102 | // But if you do understand (as a newbie): wow! 103 | 104 | int main() 105 | { 106 | *(unsigned int*)0x04000000 = 0x0403; 107 | 108 | ((unsigned short*)0x06000000)[120+80*240] = 0x001F; 109 | ((unsigned short*)0x06000000)[136+80*240] = 0x03E0; 110 | ((unsigned short*)0x06000000)[120+96*240] = 0x7C00; 111 | 112 | while(1); 113 | 114 | return 0; 115 | } 116 | ``` 117 | 118 | And save this file as `main.c`. 119 | 120 | ### Defining the project 121 | 122 | Create a new file next to `main.c` and call it `CMakeLists.txt`. You can consider this our "project" file. 123 | 124 | gba-toolchain requires CMake 3.18, so we start off by declaring this at the top of the CMakeLists.txt 125 | 126 | ```cmake 127 | cmake_minimum_required(VERSION 3.18) 128 | ``` 129 | 130 | We then give our project a name, and declare the programming language it will use, which is C. I named my project "My GBA Project". 131 | 132 | ```cmake 133 | project("My GBA Project" C) 134 | ``` 135 | 136 | We'll add an executable to this project, we'll call it "gba-game" for now. We'll also be compiling this into a [.ELF](https://en.wikipedia.org/wiki/Executable_and_Linkable_Format) file at first, so we'll add ".elf" as a suffix on "my_executable". 137 | 138 | ```cmake 139 | add_executable(gba-game main.c) 140 | set_target_properties(gba-game PROPERTIES SUFFIX ".elf") 141 | ``` 142 | 143 | That should be enough to get things going for now. The complete CMakeLists.txt should look like: 144 | 145 | ```cmake 146 | cmake_minimum_required(VERSION 3.18) 147 | 148 | project("My GBA Project" C) 149 | 150 | add_executable(gba-game main.c) 151 | set_target_properties(gba-game PROPERTIES SUFFIX ".elf") 152 | ``` 153 | 154 | ### Compiling the project 155 | 156 | We need to tell both VSCode and CMake about gba-toolchain, otherwise it won't know about the compilers or tools we want to use. 157 | 158 | To do so, we need to create a "kit", which is what VSCode uses to define CMake toolchains. 159 | 160 | We need to create a configuration folder for VSCode. Click the New Folder button and name this folder ".vscode" 161 | 162 | VSCode with a red arrow pointing at the New Folder button 163 | 164 | Once we have our VSCode configuration folder, add a new file to it called "cmake-kits.json". 165 | 166 | We will define our CMake toolchain in cmake-kits.json. Give it a name, I called mine "ARM GBA Toolchain", and also add a field for the CMake toolchain file. 167 | 168 | ```json 169 | [ 170 | { 171 | "name": "ARM GBA Toolchain", 172 | "toolchainFile": "" 173 | } 174 | ] 175 | ``` 176 | 177 | Now, remember where you put the gba-toolchain when you downloaded it at the start? You should have in there a CMake toolchain file called "arm-gba-toolchain.cmake". Copy the path to this file, including the arm-gba-toolchain.cmake, and paste it into the `toolchainFile` field in the cmake-kits.json. 178 | 179 | My toolchain is in my C: drive, so my kit looks like this: 180 | 181 | ```json 182 | [ 183 | { 184 | "name": "ARM GBA Toolchain", 185 | "toolchainFile": "C:\\gba-toolchain\\arm-gba-toolchain.cmake" 186 | } 187 | ] 188 | ``` 189 | 190 | Remember on Windows to escape the backslashes by typing two of them! `\\` 191 | 192 | We've changed a fair bit about this project, so to wake VSCode up to our changes **close and reopen VSCode**. 193 | 194 | I'll wait here whilst you do that. Done it? Cool. 195 | 196 | Now when you reopen the project folder VSCode will probably ask you if you want to configure it. 197 | 198 | VSCode configure dialogue with a red arrow pointing at the Yes button 199 |   200 | 201 | Click Yes to this and VSCode should now display some output whilst it configures. 202 | 203 | If you look at the output, you should see that it detects our kit with `[kit] Successfully loaded 1 kits from blah blah blah` 204 | 205 | VSCode output display showing successfully loaded kits 206 |   207 | 208 | We can now select our kit and compile our GBA program! 209 | 210 | Click the little "No active kit" button at the bottom of VSCode. 211 | 212 | VSCode with a red arrow pointing at the No active kit button 213 |   214 | 215 | And this will display a toolkit search area, where you can type in the name you gave your toolkit (so for me it is "ARM GBA Toolchain") and you can select it. 216 | 217 | VSCode with a red arrow pointing at the No active kit button 218 |   219 | 220 | So now we hit Build and... 221 | 222 | VSCode with a red arrow pointing at the Build button 223 |   224 | 225 | Oof! 226 | 227 | Build fail error 228 |   229 | 230 | Linker error. 231 | 232 | We've managed to compile the main.c file, but we're missing a GBA implementation of the compiler runtime. 233 | 234 | Well, now that we have our gba-toolchain kit we can do that. 235 | 236 | ### Link a GBA runtime 237 | 238 | gba-toolchain comes with runtimes for building ROMs, Multiboot images, and e-Reader binaries. 239 | 240 | These runtimes are provided as libraries, and gba-toolchain provides a special CMake function for adding these libraries to a project: `gba_add_library_subdirectory` 241 | 242 | The ROM runtime (librom) is available under the name "rom". So let's add that to our CMakeLists.txt file: 243 | 244 | ```cmake 245 | cmake_minimum_required(VERSION 3.20) 246 | 247 | project("My GBA Project" C) 248 | 249 | add_executable(gba-game main.c) 250 | set_target_properties(gba-game PROPERTIES SUFFIX ".elf") 251 | 252 | gba_add_library_subdirectory(rom) 253 | ``` 254 | 255 | And we link it with CMake's `target_link_libraries` function: 256 | 257 | ```cmake 258 | cmake_minimum_required(VERSION 3.18) 259 | 260 | project("My GBA Project" C) 261 | 262 | add_executable(gba-game main.c) 263 | set_target_properties(gba-game PROPERTIES SUFFIX ".elf") 264 | 265 | gba_add_library_subdirectory(rom) 266 | 267 | target_link_libraries(gba-game PRIVATE rom) 268 | ``` 269 | 270 | Now that we have a ROM runtime, let's try building again and see what we get. 271 | 272 | Build success 273 |   274 | 275 | Exit code 0 means success, we've managed to link our ROM runtime and produced "gba-game.elf". 276 | 277 | The emulator [mGBA](http://mgba.io/) actually supports loading ELF files as ROMs, so let's use mGBA to run our ELF file in the `build` folder and see what we get. 278 | 279 | mGBA displaying our program 280 |   281 | 282 | And that's our first GBA demo. 283 | 284 | *** 285 | 286 | 1 The [Tonc](https://www.coranac.com/tonc/text/first.htm) GBA tutorial is a legendary tutorial + development library that covers a lot of the GBA functionality. 287 | -------------------------------------------------------------------------------- /_03_helloworld/tonc.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: "Hello, World!" 4 | ordering: 1 5 | --- 6 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | remote_theme: pages-themes/primer@v0.6.0 2 | plugins: 3 | - jekyll-remote-theme 4 | 5 | title: GBA Tutorial 6 | author: Felix Jones 7 | email: felix@felixjones.co.uk 8 | description: > # this means to ignore newlines until "baseurl:" 9 | A tutorial for writing GBA homebrew software in the modern age. 10 | 11 | # social links 12 | twitter_username: Xilefian # DO NOT include the @ character, or else the build will fail! 13 | github_username: felixjones # DO NOT include the @ character, or else the build will fail! 14 | 15 | show_excerpts: true # set to false to remove excerpts on the homepage 16 | 17 | collections: 18 | 01_introduction: 19 | title: Introduction 20 | output: true 21 | order: 22 | - history.md 23 | - architecture.md 24 | - display.md 25 | - sound.md 26 | 02_setup: 27 | title: Compiling a GBA ROM 28 | output: true 29 | order: 30 | - toolchain.md 31 | - debugging.md 32 | - real-gba.md 33 | 03_helloworld: 34 | title: Hello, World! 35 | output: true 36 | - tonc.md 37 | -------------------------------------------------------------------------------- /_includes/anchor_headings.html: -------------------------------------------------------------------------------- 1 | {% capture headingsWorkspace %} 2 | {% comment %} 3 | Copyright (c) 2018 Vladimir "allejo" Jimenez 4 | 5 | Permission is hereby granted, free of charge, to any person 6 | obtaining a copy of this software and associated documentation 7 | files (the "Software"), to deal in the Software without 8 | restriction, including without limitation the rights to use, 9 | copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the 11 | Software is furnished to do so, subject to the following 12 | conditions: 13 | 14 | The above copyright notice and this permission notice shall be 15 | included in all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 19 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 20 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 21 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 22 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 23 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 24 | OTHER DEALINGS IN THE SOFTWARE. 25 | {% endcomment %} 26 | {% comment %} 27 | Version 1.0.11 28 | https://github.com/allejo/jekyll-anchor-headings 29 | 30 | "Be the pull request you wish to see in the world." ~Ben Balter 31 | 32 | Usage: 33 | {% include anchor_headings.html html=content anchorBody="#" %} 34 | 35 | Parameters: 36 | * html (string) - the HTML of compiled markdown generated by kramdown in Jekyll 37 | 38 | Optional Parameters: 39 | * beforeHeading (bool) : false - Set to true if the anchor should be placed _before_ the heading's content 40 | * headerAttrs (string) : '' - Any custom HTML attributes that will be added to the heading tag; you may NOT use `id`; 41 | the `%heading%` and `%html_id%` placeholders are available 42 | * anchorAttrs (string) : '' - Any custom HTML attributes that will be added to the `` tag; you may NOT use `href`, `class` or `title`; 43 | the `%heading%` and `%html_id%` placeholders are available 44 | * anchorBody (string) : '' - The content that will be placed inside the anchor; the `%heading%` placeholder is available 45 | * anchorClass (string) : '' - The class(es) that will be used for each anchor. Separate multiple classes with a space 46 | * anchorTitle (string) : '' - The `title` attribute that will be used for anchors 47 | * h_min (int) : 1 - The minimum header level to build an anchor for; any header lower than this value will be ignored 48 | * h_max (int) : 6 - The maximum header level to build an anchor for; any header greater than this value will be ignored 49 | * bodyPrefix (string) : '' - Anything that should be inserted inside of the heading tag _before_ its anchor and content 50 | * bodySuffix (string) : '' - Anything that should be inserted inside of the heading tag _after_ its anchor and content 51 | * generateId (true) : false - Set to true if a header without id should generate an id to use. 52 | 53 | Output: 54 | The original HTML with the addition of anchors inside of all of the h1-h6 headings. 55 | {% endcomment %} 56 | 57 | {% assign minHeader = include.h_min | default: 1 %} 58 | {% assign maxHeader = include.h_max | default: 6 %} 59 | {% assign beforeHeading = include.beforeHeading %} 60 | {% assign headerAttrs = include.headerAttrs %} 61 | {% assign nodes = include.html | split: ' 76 | {% if headerLevel == 0 %} 77 | 78 | {% assign firstChunk = node | split: '>' | first %} 79 | 80 | 81 | {% unless firstChunk contains '<' %} 82 | {% capture node %}{% endcapture %} 90 | {% assign _workspace = node | split: _closingTag %} 91 | {% capture _hAttrToStrip %}{{ _workspace[0] | split: '>' | first }}>{% endcapture %} 92 | {% assign header = _workspace[0] | replace: _hAttrToStrip, '' %} 93 | {% assign escaped_header = header | strip_html | strip %} 94 | 95 | {% assign _classWorkspace = _workspace[0] | split: 'class="' %} 96 | {% assign _classWorkspace = _classWorkspace[1] | split: '"' %} 97 | {% assign _html_class = _classWorkspace[0] %} 98 | 99 | {% if _html_class contains "no_anchor" %} 100 | {% assign skip_anchor = true %} 101 | {% else %} 102 | {% assign skip_anchor = false %} 103 | {% endif %} 104 | 105 | {% assign _idWorkspace = _workspace[0] | split: 'id="' %} 106 | {% if _idWorkspace[1] %} 107 | {% assign _idWorkspace = _idWorkspace[1] | split: '"' %} 108 | {% assign html_id = _idWorkspace[0] %} 109 | {% elsif include.generateId %} 110 | 111 | {% assign html_id = escaped_header | slugify %} 112 | {% if html_id == "" %} 113 | {% assign html_id = false %} 114 | {% endif %} 115 | {% capture headerAttrs %}{{ headerAttrs }} id="%html_id%"{% endcapture %} 116 | {% endif %} 117 | 118 | 119 | {% capture anchor %}{% endcapture %} 120 | 121 | {% if skip_anchor == false and html_id and headerLevel >= minHeader and headerLevel <= maxHeader %} 122 | {% if headerAttrs %} 123 | {% capture _hAttrToStrip %}{{ _hAttrToStrip | split: '>' | first }} {{ headerAttrs | replace: '%heading%', escaped_header | replace: '%html_id%', html_id }}>{% endcapture %} 124 | {% endif %} 125 | 126 | {% capture anchor %}href="#{{ html_id }}"{% endcapture %} 127 | 128 | {% if include.anchorClass %} 129 | {% capture anchor %}{{ anchor }} class="{{ include.anchorClass }}"{% endcapture %} 130 | {% endif %} 131 | 132 | {% if include.anchorTitle %} 133 | {% capture anchor %}{{ anchor }} title="{{ include.anchorTitle | replace: '%heading%', escaped_header }}"{% endcapture %} 134 | {% endif %} 135 | 136 | {% if include.anchorAttrs %} 137 | {% capture anchor %}{{ anchor }} {{ include.anchorAttrs | replace: '%heading%', escaped_header | replace: '%html_id%', html_id }}{% endcapture %} 138 | {% endif %} 139 | 140 | {% capture anchor %}{{ include.anchorBody | replace: '%heading%', escaped_header | default: '' }}{% endcapture %} 141 | 142 | 143 | {% if beforeHeading %} 144 | {% capture anchor %}{{ anchor }} {% endcapture %} 145 | {% else %} 146 | {% capture anchor %} {{ anchor }}{% endcapture %} 147 | {% endif %} 148 | {% endif %} 149 | 150 | {% capture new_heading %} 151 | 160 | {% endcapture %} 161 | 162 | 165 | {% assign chunkCount = _workspace | size %} 166 | {% if chunkCount > 1 %} 167 | {% capture new_heading %}{{ new_heading }}{{ _workspace | last }}{% endcapture %} 168 | {% endif %} 169 | 170 | {% capture edited_headings %}{{ edited_headings }}{{ new_heading }}{% endcapture %} 171 | {% endfor %} 172 | {% endcapture %}{% assign headingsWorkspace = '' %}{{ edited_headings | strip }} 173 | -------------------------------------------------------------------------------- /_includes/toc.html: -------------------------------------------------------------------------------- 1 | {% capture tocWorkspace %} 2 | {% comment %} 3 | Copyright (c) 2017 Vladimir "allejo" Jimenez 4 | 5 | Permission is hereby granted, free of charge, to any person 6 | obtaining a copy of this software and associated documentation 7 | files (the "Software"), to deal in the Software without 8 | restriction, including without limitation the rights to use, 9 | copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the 11 | Software is furnished to do so, subject to the following 12 | conditions: 13 | 14 | The above copyright notice and this permission notice shall be 15 | included in all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 19 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 20 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 21 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 22 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 23 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 24 | OTHER DEALINGS IN THE SOFTWARE. 25 | {% endcomment %} 26 | {% comment %} 27 | Version 1.2.0 28 | https://github.com/allejo/jekyll-toc 29 | 30 | "...like all things liquid - where there's a will, and ~36 hours to spare, there's usually a/some way" ~jaybe 31 | 32 | Usage: 33 | {% include toc.html html=content sanitize=true class="inline_toc" id="my_toc" h_min=2 h_max=3 %} 34 | 35 | Parameters: 36 | * html (string) - the HTML of compiled markdown generated by kramdown in Jekyll 37 | 38 | Optional Parameters: 39 | * sanitize (bool) : false - when set to true, the headers will be stripped of any HTML in the TOC 40 | * class (string) : '' - a CSS class assigned to the TOC 41 | * id (string) : '' - an ID to assigned to the TOC 42 | * h_min (int) : 1 - the minimum TOC header level to use; any header lower than this value will be ignored 43 | * h_max (int) : 6 - the maximum TOC header level to use; any header greater than this value will be ignored 44 | * ordered (bool) : false - when set to true, an ordered list will be outputted instead of an unordered list 45 | * item_class (string) : '' - add custom class(es) for each list item; has support for '%level%' placeholder, which is the current heading level 46 | * submenu_class (string) : '' - add custom class(es) for each child group of headings; has support for '%level%' placeholder which is the current "submenu" heading level 47 | * base_url (string) : '' - add a base url to the TOC links for when your TOC is on another page than the actual content 48 | * anchor_class (string) : '' - add custom class(es) for each anchor element 49 | * skip_no_ids (bool) : false - skip headers that do not have an `id` attribute 50 | 51 | Output: 52 | An ordered or unordered list representing the table of contents of a markdown block. This snippet will only 53 | generate the table of contents and will NOT output the markdown given to it 54 | {% endcomment %} 55 | 56 | {% capture newline %} 57 | {% endcapture %} 58 | {% assign newline = newline | rstrip %} 59 | 60 | {% capture deprecation_warnings %}{% endcapture %} 61 | 62 | {% if include.baseurl %} 63 | {% capture deprecation_warnings %}{{ deprecation_warnings }}{{ newline }}{% endcapture %} 64 | {% endif %} 65 | 66 | {% if include.skipNoIDs %} 67 | {% capture deprecation_warnings %}{{ deprecation_warnings }}{{ newline }}{% endcapture %} 68 | {% endif %} 69 | 70 | {% capture jekyll_toc %}{% endcapture %} 71 | {% assign orderedList = include.ordered | default: false %} 72 | {% assign baseURL = include.base_url | default: include.baseurl | default: '' %} 73 | {% assign skipNoIDs = include.skip_no_ids | default: include.skipNoIDs | default: false %} 74 | {% assign minHeader = include.h_min | default: 1 %} 75 | {% assign maxHeader = include.h_max | default: 6 %} 76 | {% assign nodes = include.html | strip | split: ' maxHeader %} 92 | {% continue %} 93 | {% endif %} 94 | 95 | {% assign _workspace = node | split: '' | first }}>{% endcapture %} 114 | {% assign header = _workspace[0] | replace: _hAttrToStrip, '' %} 115 | 116 | {% if include.item_class and include.item_class != blank %} 117 | {% capture listItemClass %} class="{{ include.item_class | replace: '%level%', currLevel | split: '.' | join: ' ' }}"{% endcapture %} 118 | {% endif %} 119 | 120 | {% if include.submenu_class and include.submenu_class != blank %} 121 | {% assign subMenuLevel = currLevel | minus: 1 %} 122 | {% capture subMenuClass %} class="{{ include.submenu_class | replace: '%level%', subMenuLevel | split: '.' | join: ' ' }}"{% endcapture %} 123 | {% endif %} 124 | 125 | {% capture anchorBody %}{% if include.sanitize %}{{ header | strip_html }}{% else %}{{ header }}{% endif %}{% endcapture %} 126 | 127 | {% if htmlID %} 128 | {% capture anchorAttributes %} href="{% if baseURL %}{{ baseURL }}{% endif %}#{{ htmlID }}"{% endcapture %} 129 | 130 | {% if include.anchor_class %} 131 | {% capture anchorAttributes %}{{ anchorAttributes }} class="{{ include.anchor_class | split: '.' | join: ' ' }}"{% endcapture %} 132 | {% endif %} 133 | 134 | {% capture listItem %}{{ anchorBody }}{% endcapture %} 135 | {% elsif skipNoIDs == true %} 136 | {% continue %} 137 | {% else %} 138 | {% capture listItem %}{{ anchorBody }}{% endcapture %} 139 | {% endif %} 140 | 141 | {% if currLevel > lastLevel %} 142 | {% capture jekyll_toc %}{{ jekyll_toc }}<{{ listModifier }}{{ subMenuClass }}>{% endcapture %} 143 | {% elsif currLevel < lastLevel %} 144 | {% assign repeatCount = lastLevel | minus: currLevel %} 145 | 146 | {% for i in (1..repeatCount) %} 147 | {% capture jekyll_toc %}{{ jekyll_toc }}{% endcapture %} 148 | {% endfor %} 149 | 150 | {% capture jekyll_toc %}{{ jekyll_toc }}{% endcapture %} 151 | {% else %} 152 | {% capture jekyll_toc %}{{ jekyll_toc }}{% endcapture %} 153 | {% endif %} 154 | 155 | {% capture jekyll_toc %}{{ jekyll_toc }}{{ listItem }}{% endcapture %} 156 | 157 | {% assign lastLevel = currLevel %} 158 | {% assign firstHeader = false %} 159 | {% endfor %} 160 | 161 | {% assign repeatCount = minHeader | minus: 1 %} 162 | {% assign repeatCount = lastLevel | minus: repeatCount %} 163 | {% for i in (1..repeatCount) %} 164 | {% capture jekyll_toc %}{{ jekyll_toc }}{% endcapture %} 165 | {% endfor %} 166 | 167 | {% if jekyll_toc != '' %} 168 | {% assign rootAttributes = '' %} 169 | {% if include.class and include.class != blank %} 170 | {% capture rootAttributes %} class="{{ include.class | split: '.' | join: ' ' }}"{% endcapture %} 171 | {% endif %} 172 | 173 | {% if include.id and include.id != blank %} 174 | {% capture rootAttributes %}{{ rootAttributes }} id="{{ include.id }}"{% endcapture %} 175 | {% endif %} 176 | 177 | {% if rootAttributes %} 178 | {% assign nodes = jekyll_toc | split: '>' %} 179 | {% capture jekyll_toc %}<{{ listModifier }}{{ rootAttributes }}>{{ nodes | shift | join: '>' }}>{% endcapture %} 180 | {% endif %} 181 | {% endif %} 182 | {% endcapture %}{% assign tocWorkspace = '' %}{{ deprecation_warnings }}{{ jekyll_toc -}} 183 | -------------------------------------------------------------------------------- /_layouts/default.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | {% seo %} 9 | 10 | {% include head-custom.html %} 11 | 12 | 13 |
14 | {% if site.title and site.title != page.title %} 15 |

{{ site.title }}

16 | {% endif %} 17 | 18 | {{ content }} 19 | 20 | {% if site.github.private != true and site.github.license %} 21 | 24 | {% endif %} 25 |
26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /_layouts/post.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | {% if page.collection %} 4 | {% assign collections = site.collections | where_exp: "item", "item.label != 'posts'" %} 5 | 6 | {% assign oneMore = false %} 7 | {% for collection in collections %} 8 | {% if collection.label == page.collection %} 9 | {% assign oneMore = true %} 10 | {% elsif oneMore == false %} 11 | {% assign prevColPage = site[collection.label] | sort: 'ordering' | last %} 12 | {% else %} 13 | {% assign nextColPage = site[collection.label] | sort: 'ordering' | first %} 14 | {% break %} 15 | {% endif %} 16 | {% endfor %} 17 | 18 | {% assign posts = site[page.collection] | sort: 'ordering' %} 19 | 20 | {% for post in posts %} 21 | {% if post.title == page.title %} 22 | {% assign prevIndex = forloop.index0 | minus: 1 %} 23 | {% assign nextIndex = forloop.index0 | plus: 1 %} 24 | {% break %} 25 | {% endif %} 26 | {% endfor %} 27 | {% endif %} 28 | 29 | 30 | 31 | 32 | 33 | 34 | 57 | 58 | {% seo %} 59 | 60 | {% include head-custom.html %} 61 | 62 | 63 |
64 | {% if site.title and site.title != page.title %} 65 |

{{ site.title }}

66 | {% endif %} 67 | 68 | {% if page.collection %} 69 | 88 | {% endif %} 89 | 90 | {% include toc.html html=content h_min=2 %} 91 | {% include anchor_headings.html html=content %} 92 | 93 | {% if page.collection %} 94 | 113 | {% endif %} 114 | 115 | {% if site.github.private != true and site.github.license %} 116 | 119 | {% endif %} 120 |
121 | 122 | 123 | 124 | 125 | 126 | -------------------------------------------------------------------------------- /index.md: -------------------------------------------------------------------------------- 1 | # What is this? 2 | 3 | A tutorial for writing GBA homebrew software in the modern age. 4 | 5 |
    6 | {% assign collections = site.collections | where_exp: "item", "item.label != 'posts'" %} 7 | {% for collection in collections %} 8 |
  1. 9 | {{ collection.title }} 10 |
      11 | {% assign posts = site[collection.label] | sort: 'ordering' %} 12 | {% for post in posts %} 13 |
    1. {{ post.title }}
    2. 14 | {% endfor %} 15 |
    16 |
  2. 17 | {% endfor %} 18 |
19 | --------------------------------------------------------------------------------