digitalmars.D - Writing GBA games with D!
- Raimondo Mancino (185/185) May 19 2021 Hello,
- 12345swordy (4/13) May 19 2021 That isn't correct though, you just need to use llvm LLD linker.
- Raimondo Mancino (3/21) May 19 2021 I tried to use ld.lld but it doesn't seem to work.
- 12345swordy (3/26) May 19 2021 What directives that you are using anyways?
- Raimondo Mancino (3/5) May 19 2021 I didn't write the linker script myself; you can find it here
- 12345swordy (3/9) May 19 2021 What error messages are you seeing?
- Raimondo Mancino (5/9) May 19 2021 Here is an example:
- 12345swordy (6/16) May 19 2021 You shouldn't copy and paste someone else's links script without
- Raimondo Mancino (2/7) May 19 2021 But, it works for GCC.
- Raimondo Mancino (2/5) May 19 2021 I'll read it anyway; thank you for your suggestion.
- Raimondo Mancino (28/36) May 19 2021 # Edit: It works!
- Raimondo Mancino (3/5) May 19 2021 I'm sorry, I meant, to REG_DISP_CTL, because it lies in the
- TheGag96 (23/24) May 19 2021 Very cool, from a fellow Nintendo D homebrewer in arms!! I would
- Raimondo Mancino (29/51) May 20 2021 No particular reason, I just followed the first tutorial I saw
- Imperatorn (2/7) May 20 2021 👏
Hello, I've been interested into GBA game development because it's a fairly interesting device to work with. It features an ARM cpu with TDMI extensions. Here are the steps to begin with: I've been trying to make it work with LLVM too but it looks like Clang does not support GCC's linker script extensions and directives, which are required to build the CRT0 object. You need to do this because the AGB system does not have a runtime. At the time, games were mostly written in pure assembly or C without the standard library. I used latest binutils (2.36.1 at the moment of writing this thread) and used this configuration: ```sh ../configure --target=arm-none-eabi --program-prefix=gba- ``` In older GCC (prior to 4.8) you would use `arm-agb-elf` as target. As you can guess, this is an embedded SoC device, so `eabi` is fine. You need *both* GCC and GDC. To build them we need to disable a lot of stuff and use _newlib_ instead of the standard _glibc_ (since it is an embedded device). Make sure you have libmpc, limpfr and libgmp installed in your system before building. I used latest GCC (11.1.0) and configured it like this: ```sh ../configure \ --target=arm-none-eabi \ --program-prefix=gba- \ --enable-languages=c,d \ --with-newlib \ --with-multilib-list=rmprofile \ --disable-decimal-float \ --disable-libffi \ --disable-libgomp \ --disable-libmudflap \ --disable-libquadmath \ --disable-libssp \ --disable-libstdcxx-pch \ --disable-nls \ --disable-shared \ --disable-threads \ --disable-tls ``` Notice the line `--with-multilib-list=rmprofile`: without this line, the libssp needed for the build of the host toolchain would fail. Reference: https://forums.gentoo.org/viewtopic-t-1077292-start-0.html Since we specified a custom program prefix (`gba-` in my case) we need to set the required environment variables so that the configure script of newlib does not break. I used latest newlib (4.1.0). ```sh CC_FOR_TARGET=/absolute/path/to/gba-gcc \ GCC_FOR_TARGET=/absolute/path/to/gba-gcc \ AR_FOR_TARGET=/absolute/path/to/gba-ar \ AS_FOR_TARGET=/absolute/path/to/gba-as \ LD_FOR_TARGET=/absolute/path/to/gba-ld \ NM_FOR_TARGET=/absolute/path/to/gba-nm \ OBJCOPY_FOR_TARGET=/absolute/path/to/gba-objcopy \ OBJDUMP_FOR_TARGET=/absolute/path/to/gba-objdump \ RANLIB_FOR_TARGET=/absolute/path/to/gba-ranlib \ READELF_FOR_TARGET=/absolute/path/to/gba-readelf \ STRIP_FOR_TARGET=/absolute/path/to/gba-strip \ ../configure \ --target=arm-none-eabi \ --program-prefix=gba- ``` The required steps for this are simple. Versions of [Jeff Frohwein](https://www.devrs.com/)'s crt0.s prior to 1.28 do not seem to work with latest GCC. If you're using GCC prior to 4.8 older versions should work too. Here is the [referenced crt0.s](https://ghostbin.com/paste/iIvGa) Same as the previous: versions prior to 1.3 do not seem to work with latest GCC. Here is the [referenced linker script](https://ghostbin.com/paste/eHuDy) We need to produce the object files and then link them together with GCC. Here is a simple hello world program that paints the whole screen with red: ```d nogc: enum VRAM = cast(ushort*) 0x6000000; enum SCREEN_WIDTH = 240; enum SCREEN_HEIGHT = 160; enum FRAME_SEL_BIT = 0x10; enum BG2_ENABLE = 0x400; enum REG_DISP_CTL = cast(ushort*) 0x4000000; extern(C) int main() { int i; *REG_DISP_CTL = 3 | BG2_ENABLE; *REG_DISP_CTL &= ~FRAME_SEL_BIT; for(i = 0; i < SCREEN_WIDTH * SCREEN_HEIGHT; i++) { VRAM[i] = 31; } for(;;) { } return 0; } ``` The example was written after this C example: ```c #include <stdint.h> uint16_t *fb = (void*)0x6000000; const int xsz = 240; const int ysz = 160; #define FRAME_SEL_BIT 0x10 #define BG2_ENABLE 0x400 int main(void) { int i; static volatile uint16_t * const reg_disp_ctl = (void*)0x4000000; *reg_disp_ctl = 3 | BG2_ENABLE; *reg_disp_ctl &= ~FRAME_SEL_BIT; for(i=0; i<xsz * ysz; i++) { fb[i] = 31; } for(;;); return 0; } ``` Notice that `_start` is already defined by crt0, which handles I/O initialization and other useful init routines (for example, stop sound if cartridge is removed). Both `main` and `AgbMain` are valid entry points of the program. First you need to build your D files. Since we're excluding the D runtime, make sure you have at least an empty object.d in your project. ```sh gba-gdc test.d \ -O3 \ -fomit-frame-pointer \ -marm \ -mcpu=arm7tdmi \ -fno-druntime \ -c \ -pedantic \ -Wall ``` As you can notice we don't need the D runtime here. Then, assemble the crt0: ```sh gba-as crt0.S -o crt0.o ``` Now that we have built the two object files, we can just link them together and produce the ELF binary; then we create the GBA image with objcopy. ``` gba-gcc \ -o out.elf crt0.o test.o \ -Tlscript.ld \ -nostartfiles \ -lm gba-objcopy -O binary out.elf test.gba ``` At this point you can just load it into an emulator. Game fields like title and author are specified by crt0.s but you need to update the checksum flag accordingly. If you don't want to set them manually you can use [gbafix](https://github.com/devkitPro/gba-tools/). At the moment, the binary is built correctly, but it does not seem to link correctly when using D. Using GCC (for the C example above) instead of GDC with same options works so my guess is that the linker script needs to be updated. I think I need help for this; do you have any suggestions? Thank you in advance.
May 19 2021
On Wednesday, 19 May 2021 at 13:52:58 UTC, Raimondo Mancino wrote:Hello, I've been interested into GBA game development because it's a fairly interesting device to work with. It features an ARM cpu with TDMI extensions. Here are the steps to begin with: I've been trying to make it work with LLVM too but it looks like Clang does not support GCC's linker script extensions and directives, which are required to build the CRT0 object.That isn't correct though, you just need to use llvm LLD linker. It supports linker script extensions. -Alex
May 19 2021
On Wednesday, 19 May 2021 at 15:06:02 UTC, 12345swordy wrote:On Wednesday, 19 May 2021 at 13:52:58 UTC, Raimondo Mancino wrote:I tried to use ld.lld but it doesn't seem to work. It yells about unknown directives.Hello, I've been interested into GBA game development because it's a fairly interesting device to work with. It features an ARM cpu with TDMI extensions. Here are the steps to begin with: I've been trying to make it work with LLVM too but it looks like Clang does not support GCC's linker script extensions and directives, which are required to build the CRT0 object.That isn't correct though, you just need to use llvm LLD linker. It supports linker script extensions. -Alex
May 19 2021
On Wednesday, 19 May 2021 at 15:17:13 UTC, Raimondo Mancino wrote:On Wednesday, 19 May 2021 at 15:06:02 UTC, 12345swordy wrote:What directives that you are using anyways? -AlexOn Wednesday, 19 May 2021 at 13:52:58 UTC, Raimondo Mancino wrote:I tried to use ld.lld but it doesn't seem to work. It yells about unknown directives.Hello, I've been interested into GBA game development because it's a fairly interesting device to work with. It features an ARM cpu with TDMI extensions. Here are the steps to begin with: I've been trying to make it work with LLVM too but it looks like Clang does not support GCC's linker script extensions and directives, which are required to build the CRT0 object.That isn't correct though, you just need to use llvm LLD linker. It supports linker script extensions. -Alex
May 19 2021
On Wednesday, 19 May 2021 at 18:28:49 UTC, 12345swordy wrote:What directives that you are using anyways? -AlexI didn't write the linker script myself; you can find it here https://ghostbin.com/paste/eHuDy
May 19 2021
On Wednesday, 19 May 2021 at 21:33:07 UTC, Raimondo Mancino wrote:On Wednesday, 19 May 2021 at 18:28:49 UTC, 12345swordy wrote:What error messages are you seeing? -AlexWhat directives that you are using anyways? -AlexI didn't write the linker script myself; you can find it here https://ghostbin.com/paste/eHuDy
May 19 2021
On Wednesday, 19 May 2021 at 22:09:56 UTC, 12345swordy wrote:What error messages are you seeing? -AlexHere is an example: ``` ld.lld: error: lscript.ld:199: malformed number: :```OVERLAY : NOCROSSREFS AT (__iwram_overlay_lma)
May 19 2021
On Wednesday, 19 May 2021 at 22:15:25 UTC, Raimondo Mancino wrote:On Wednesday, 19 May 2021 at 22:09:56 UTC, 12345swordy wrote:You shouldn't copy and paste someone else's links script without understanding how it works. Please read the documentation on the linker script. https://ftp.gnu.org/old-gnu/Manuals/ld-2.9.1/html_chapter/ld_3.html -AlexWhat error messages are you seeing? -AlexHere is an example: ``` ld.lld: error: lscript.ld:199: malformed number: :```OVERLAY : NOCROSSREFS AT (__iwram_overlay_lma)
May 19 2021
On Wednesday, 19 May 2021 at 22:23:00 UTC, 12345swordy wrote:You shouldn't copy and paste someone else's links script without understanding how it works. Please read the documentation on the linker script. https://ftp.gnu.org/old-gnu/Manuals/ld-2.9.1/html_chapter/ld_3.html -AlexBut, it works for GCC.
May 19 2021
On Wednesday, 19 May 2021 at 22:23:00 UTC, 12345swordy wrote:Please read the documentation on the linker script. https://ftp.gnu.org/old-gnu/Manuals/ld-2.9.1/html_chapter/ld_3.html -AlexI'll read it anyway; thank you for your suggestion.
May 19 2021
On Wednesday, 19 May 2021 at 13:52:58 UTC, Raimondo Mancino wrote:At the moment, the binary is built correctly, but it does not seem to link correctly when using D. Using GCC (for the C example above) instead of GDC with same options works so my guess is that the linker script needs to be updated. I think I need help for this; do you have any suggestions? Thank you in advance.To make it work correctly, you need to use volatile reference to VRAM. So the correct hello world program is: ```d import core.volatile; nogc: enum VRAM = cast(ushort*) 0x6000000; enum SCREEN_WIDTH = 240; enum SCREEN_HEIGHT = 160; enum FRAME_SEL_BIT = 0x10; enum BG2_ENABLE = 0x400; enum REG_DISP_CTL = cast(ushort*) 0x4000000; extern(C) int main() { int i; volatileStore(REG_DISP_CTL, 3 | BG2_ENABLE); volatileStore(REG_DISP_CTL, volatileLoad(REG_DISP_CTL) & ~FRAME_SEL_BIT); for(i = 0; i < SCREEN_WIDTH * SCREEN_HEIGHT; i++) { VRAM[i] = 31; } for(;;) { } return 0; } ``` Since we used -fno-druntime, core/volatile.d needs to be included in our project.
May 19 2021
On Wednesday, 19 May 2021 at 15:59:33 UTC, Raimondo Mancino wrote:To make it work correctly, you need to use volatile reference to VRAM.I'm sorry, I meant, to REG_DISP_CTL, because it lies in the section at 0x6000000 of the AGB system.
May 19 2021
On Wednesday, 19 May 2021 at 13:52:58 UTC, Raimondo Mancino wrote:(snip)Very cool, from a fellow Nintendo D homebrewer in arms!! I would love to see more people using the language this way. I myself am having a lot of fun writing a game in D for the 3DS - here's a basic [hello world + bindings](https://github.com/TheGag96/3ds-hello-dlang) that I almost certainly need to update. I'm kind of shocked you're not using [devkitARM](https://github.com/devkitPro/gba-examples). Any reason? At first, I modified the toolchain to compile D support into GCC, but like someone already suggested here, I'm using LDC now and am not looking back. Definitely recommend doing so. DevkitARM uses Newlib also, and D unfortunately doesn't yet have bindings for it yet. In my repo, you'll see that I had to kind of study Newlib's header files and try to hack into druntime in myself. LDC made a change recently that reserves the version `CRuntime_Newlib`, so you will probably have to something similar to what I did but call it `CRuntime_Gba` or something. Hopefully it'll get first class support down the road (people actually looking to use it like you and I should probably be taking up the charge, honestly lol). Just curious, what kind of game/app are you looking to make with this?
May 19 2021
On Thursday, 20 May 2021 at 03:30:40 UTC, TheGag96 wrote:Very cool, from a fellow Nintendo D homebrewer in arms!! I would love to see more people using the language this way. I myself am having a lot of fun writing a game in D for the 3DS - here's a basic [hello world + bindings](https://github.com/TheGag96/3ds-hello-dlang) that I almost certainly need to update.Very interesting!I'm kind of shocked you're not using [devkitARM](https://github.com/devkitPro/gba-examples). Any reason? At first, I modified the toolchain to compile D support into GCC, but like someone already suggested here, I'm using LDC now and am not looking back. Definitely recommend doing so.No particular reason, I just followed the first tutorial I saw and it used GCC. The article in question is this http://nuclear.mutantstargoat.com/articles/gba_dev_tools.html I'm a complete newbie with this :) At first I was doing it with LDC as well, but I didn't manage to build a working binary. I tried with: ```sh ldc2 test.d -betterC -mtriple=arm-none-eabi -float-abi=soft -singleobj -c -nogc -static llvm-strip test.o -o test.o --strip-all --strip-all-gnu --remove-section .ARM.exidx ld.gold -Tlscript.ld -o out.elf crt0.o test.o gba-objcopy -O binary out.elf test.gba ``` where crt0 is the same one I used in this thread. I used gold and not lld because lld doesn't support (or I didn't manage to make it work) the syntax used in the script. I am not very familiar with linker scripts yet, but I'm trying to write my own for GCC now.DevkitARM uses Newlib also, and D unfortunately doesn't yet have bindings for it yet. In my repo, you'll see that I had to kind of study Newlib's header files and try to hack into druntime in myself. LDC made a change recently that reserves the version `CRuntime_Newlib`, so you will probably have to something similar to what I did but call it `CRuntime_Gba` or something. Hopefully it'll get first class support down the road (people actually looking to use it like you and I should probably be taking up the charge, honestly lol).It's interesting though... I'll look into it. I really didn't make much research, just tried right away.Just curious, what kind of game/app are you looking to make with this?I was considering to create a step sequencer at first so I can get used to audio and gui stuff. I'll then try to write a game with j-rpg mechanics, but it's going to be a little different than your usual j-rpg.
May 20 2021
On Thursday, 20 May 2021 at 09:08:58 UTC, Raimondo Mancino wrote:I was considering to create a step sequencer at first so I can get used to audio and gui stuff. I'll then try to write a game with j-rpg mechanics, but it's going to be a little different than your usual j-rpg.I see, nice! Hope you have fun with it. Feel free to post back here from time to time about how things are going. I updated my repo with changes to bindings and druntime/Phobos edits - hopefully it's of some use to you or anyone else.
May 20 2021
On Thursday, 20 May 2021 at 21:18:15 UTC, TheGag96 wrote:I updated my repo with changes to bindings and druntime/Phobos edits - hopefully it's of some use to you or anyone else.I just wanted to share, based on TheGag96's work porting D to devkitarm 3DS, I have successfully ported D to GBA along with D headers for the entirety of libtonc. https://github.com/redthing1/gba_dlang https://beanmachine.alt.icu/post/d_on_gba/ This pretty much gives you drop in, full support for D on GBA (in betterC mode of course). With this, you can write GBA games with dlang! It's Dlang on GBA!
Feb 08 2022
On Wednesday, 19 May 2021 at 13:52:58 UTC, Raimondo Mancino wrote:Hello, I've been interested into GBA game development because it's a fairly interesting device to work with. It features an ARM cpu with TDMI extensions. [...]👏
May 20 2021