rust-console / gba Goto Github PK
View Code? Open in Web Editor NEWA crate that helps you make GBA games
Home Page: https://docs.rs/gba
License: Apache License 2.0
A crate that helps you make GBA games
Home Page: https://docs.rs/gba
License: Apache License 2.0
There is a set of C test roms: https://github.com/mgba-emu/suite
We can use them as part of a usability and coverage test. Basically we want to write the C test rom in Rust as rustily as possible, and then make sure the crate supports thay code well, ideally with zero unsafe needed in the test rom code.
We want to add a way to get the address of the end of the BSS section that is filled by the linker. Something like this
extern {
static __bss_end: ();
}
I found this tutorial
http://members.iinet.net.au/~freeaxs/gbacomp/
Probably want to vet it a bit before including it in the guide, but it seems useful.
Right now there's a little commenting, but it's still kinda mysterious.
I think it'd be a good segment to add to the end of the "GBA Assembly" lesson if we put the entire crt0.s
file with a comment on every line and a breakdown of why we're doing the different steps and stuff.
.data
to IWRAM but not .bss
, is this just a legacy thing because .bss
wasn't used at first?gbafix
does exactly?CpuSet
, correct? After that, the control flow just "falls through" into the next block and jumps to main, right?swi 0
and swi 1
will interact with what crt0.s
defines.And any other notes and explanations you think a beginner would need!
Thanks to oli
for suggesting this style
#[repr(align(4))] struct Wrapper<T>(T);
pub const A: &[u8] = &Wrapper(*include_bytes!("file.img")).0;
I see no sign of dynamic allocation in source files and all examples are compiled with no_std
flag, causing no built-in allocator. So how heap memory is managed in this crate?
0x400_00B0
, 4, W, DMA0SAD, DMA 0 Source Address0x400_00B4
, 4, W, DMA0DAD, DMA 0 Destination Address0x400_00B8
, 2, W, DMA0CNT_L, DMA 0 Word Count0x400_00BA
, 2, R/W, DMA0CNT_H, DMA 0 Control0x400_00BC
, 4, W, DMA1SAD, DMA 1 Source Address0x400_00C0
, 4, W, DMA1DAD, DMA 1 Destination Address0x400_00C4
, 2, W, DMA1CNT_L, DMA 1 Word Count0x400_00C6
, 2, R/W, DMA1CNT_H, DMA 1 Control0x400_00C8
, 4, W, DMA2SAD, DMA 2 Source Address0x400_00CC
, 4, W, DMA2DAD, DMA 2 Destination Address0x400_00D0
, 2, W, DMA2CNT_L, DMA 2 Word Count0x400_00D2
, 2, R/W, DMA2CNT_H, DMA 2 Control0x400_00D4
, 4, W, DMA3SAD, DMA 3 Source Address0x400_00D8
, 4, W, DMA3DAD, DMA 3 Destination Address0x400_00DC
, 2, W, DMA3CNT_L, DMA 3 Word Count0x400_00DE
, 2, R/W, DMA3CNT_H, DMA 3 Control0x400_00E0
, Not usedFor things like clearing the screen in bitmap modes we're currently using a thumb state u32 write but that's still not fast enough.
There is an assembly instruction for writing even more at once (stmia), which is what CpuFastSet uses, and we need to check if LLVM is generating this instruction or not.
If we get it going in user code instead of doing the bios call we save time on the mode switching from user to system and back.
0x400_0100
, 2, R/W, TM0CNT_L, Timer 0 Counter/Reload0x400_0102
, 2, R/W, TM0CNT_H, Timer 0 Control0x400_0104
, 2, R/W, TM1CNT_L, Timer 1 Counter/Reload0x400_0106
, 2, R/W, TM1CNT_H, Timer 1 Control0x400_0108
, 2, R/W, TM2CNT_L, Timer 2 Counter/Reload0x400_010A
, 2, R/W, TM2CNT_H, Timer 2 Control0x400_010C
, 2, R/W, TM3CNT_L, Timer 3 Counter/Reload0x400_010E
, 2, R/W, TM3CNT_H, Timer 3 Control0x400_0110
, Not usedWe should add an offset method.
Ubsan says that for the purposes of IO Register stuff on the GBA it doesn't need to be wrapping_offset, so we'll just use normal offset.
0x400_0000
, 2, R/W, DISPCNT , LCD Control0x400_0002
, 2, R/W, Undocumented - Green Swap0x400_0004
, 2, R/W, DISPSTAT, General LCD Status (STAT,LYC)0x400_0006
, 2, R, VCOUNT, Vertical Counter (LY)0x400_0008
, 2, R/W, BG0CNT, BG0 Control0x400_000A
, 2, R/W, BG1CNT, BG1 Control0x400_000C
, 2, R/W, BG2CNT, BG2 Control0x400_000E
, 2, R/W, BG3CNT, BG3 Control0x400_0010
, 2, W, BG0HOFS, BG0 X-Offset0x400_0012
, 2, W, BG0VOFS, BG0 Y-Offset0x400_0014
, 2, W, BG1HOFS, BG1 X-Offset0x400_0016
, 2, W, BG1VOFS, BG1 Y-Offset0x400_0018
, 2, W, BG2HOFS, BG2 X-Offset0x400_001A
, 2, W, BG2VOFS, BG2 Y-Offset0x400_001C
, 2, W, BG3HOFS, BG3 X-Offset0x400_001E
, 2, W, BG3VOFS, BG3 Y-Offset0x400_0020
, 2, W, BG2PA, BG2 Rotation/Scaling Parameter A (dx)0x400_0022
, 2, W, BG2PB, BG2 Rotation/Scaling Parameter B (dmx)0x400_0024
, 2, W, BG2PC, BG2 Rotation/Scaling Parameter C (dy)0x400_0026
, 2, W, BG2PD, BG2 Rotation/Scaling Parameter D (dmy)0x400_0028
, 4, W, BG2X, BG2 Reference Point X-Coordinate0x400_002C
, 4, W, BG2Y, BG2 Reference Point Y-Coordinate0x400_0030
, 2, W, BG3PA, BG3 Rotation/Scaling Parameter A (dx)0x400_0032
, 2, W, BG3PB, BG3 Rotation/Scaling Parameter B (dmx)0x400_0034
, 2, W, BG3PC, BG3 Rotation/Scaling Parameter C (dy)0x400_0036
, 2, W, BG3PD, BG3 Rotation/Scaling Parameter D (dmy)0x400_0038
, 4, W, BG3X, BG3 Reference Point X-Coordinate0x400_003C
, 4, W, BG3Y, BG3 Reference Point Y-Coordinate0x400_0040
, 2, W, WIN0H, Window 0 Horizontal Dimensions0x400_0042
, 2, W, WIN1H, Window 1 Horizontal Dimensions0x400_0044
, 2, W, WIN0V, Window 0 Vertical Dimensions0x400_0046
, 2, W, WIN1V, Window 1 Vertical Dimensions0x400_0048
, 2, R/W, WININ, Inside of Window 0 and 10x400_004A
, 2, R/W, WINOUT, Inside of OBJ Window & Outside of Windows0x400_004C
, 2, W, MOSAIC, Mosaic Size0x400_004E
, Not used0x400_0050
, 2, R/W, BLDCNT, Color Special Effects Selection0x400_0052
, 2, R/W, BLDALPHA, Alpha Blending Coefficients0x400_0054
, 2, W, BLDY, Brightness (Fade-In/Out) Coefficient0x400_0056
, Not used0x400_0120
, 4, R/W, SIODATA32, SIO Data (Normal-32bit Mode; shared with below)0x400_0120
, 2, R/W, SIOMULTI0, SIO Data 0 (Parent) (Multi-Player Mode)0x400_0122
, 2, R/W, SIOMULTI1, SIO Data 1 (1st Child) (Multi-Player Mode)0x400_0124
, 2, R/W, SIOMULTI2, SIO Data 2 (2nd Child) (Multi-Player Mode)0x400_0126
, 2, R/W, SIOMULTI3, SIO Data 3 (3rd Child) (Multi-Player Mode)0x400_0128
, 2, R/W, SIOCNT, SIO Control Register0x400_012A
, 2, R/W, SIOMLT_SEND, SIO Data (Local of MultiPlayer; shared below)0x400_012A
, 2, R/W, SIODATA8, SIO Data (Normal-8bit and UART Mode)0x400_012C
, Not usedTrying to compile a program containing a (non-elided) static mut
produces some delightful linker spew:
= note: arm-none-eabi-ld: warning: cannot find entry symbol __start; defaulting to 0000000008000000
`.bss._ZN16fox_flux_advance4test17h9ec3708eaa2e7c78E' referenced in section `.text._ZN16fox_flux_advance4step17hd2b45f0f3bd89611E' of /home/eevee/dev/fox-flux-advance.git/target/thumbv4-none-agb/debug/deps/fox_flux_advance-3341f37616403a6a.3y0pnfisrximx3xe.rcgu.o: defined
in discarded section `.bss._ZN16fox_flux_advance4test17h9ec3708eaa2e7c78E' of /home/eevee/dev/fox-flux-advance.git/target/thumbv4-none-agb/debug/deps/fox_flux_advance-3341f37616403a6a.3y0pnfisrximx3xe.rcgu.o
Linkers aren't my area, but the problem seems to be that globals go in .bss
sections, and those are dropped by the linker script. Adding this fixed it for me:
.bss : {
*(.bss .bss.*);
. = ALIGN(4);
} >iwram = 0xff
No idea if iwram
is appropriate or not. Please let me know if not. ;)
We can probably make the line drawing faster by special casing some things.
So right now it only does cargo check and cargo check --release
We want to build all examples if possible. For this we need to setup devkitpro within the travis cache, which probably isn't too hard.
We want to be able to run tests so that we can write tests. Step 1 is to make the no_std tag on thr library be cfg_attr(not(test), no_std). Step 2 is to possibly cfg various lines so that things depending on the memory map only happen on the agb. I'm not sure we need tests for those things at all, but it'd be nice to not footgun.
A lot of functions / methods aren't inlined with #[inline]
when it might be beneficial to do so. For example I think it's good to inline the new
method when using the newtype
macro.
Anything in the book/src-bak
needs to be sorted into a real part of the book or thrown out
Does it spark joy?
0x400_0134
, 2, R/W, RCNT, SIO Mode Select/General Purpose Data0x400_0136
, IR, Ancient - Infrared Register (Prototypes only)0x400_0138
, Not used0x400_0140
, 2, R/W, JOYCNT, SIO JOY Bus Control0x400_0142
, Not used0x400_0150
, 4, R/W, JOY_RECV, SIO JOY Bus Receive Data0x400_0154
, 4, R/W, JOY_TRANS, SIO JOY Bus Transmit Data0x400_0158
, 2, R/?, JOYSTAT, SIO JOY Bus Receive Status0x400_015A
, Not usedThe current version of VolatilePtr<T>
isn't the best. Obvious ways to improve include:
derive
attribute actually only derives if T
has the trait in question, even though the pointer field itself will always support the requested traits regardless of what T
actually is. We want to enforce that the traits in question are always present regardless of T
.NonNull
so that the Option<VolatilePtr<_>>
during the from the iteration don't need extra tag bits. Which also then means we have to store a PhantomData<Cell<T>>
as well for invariance to hold, meaning that VolatilePtr<T>
literals end up quite wordy, and we'd want some constructor methods.const
if possible. That may require that we store NonZeroUsize
and cast it into a *mut T
at the last minute for reads and writes. This also requires some PhantomData<_>
, to keep the type of the faked pointer tracked, though it could be T
directly instead of needing to be Cell<T>
.We have to clean out the examples-bak
directory into either real code or throw it out entirely.
Does it spark joy?
0x400_0200
, 2, R/W, IE, Interrupt Enable Register0x400_0202
, 2, R/W, IF, Interrupt Request Flags / IRQ Acknowledge0x400_0204
, 2, R/W, WAITCNT, Game Pak Waitstate Control0x400_0206
, Not used0x400_0208
, 2, R/W, IME, Interrupt Master Enable Register0x400_020A
, Not used0x400_0300
, 1, R/W, POSTFLG, Undocumented - Post Boot Flag0x400_0301
, 1, W, HALTCNT, Undocumented - Power Down Control0x400_0302
, Not used0x400_0410
, Undocumented - Purpose Unknown / Bug ??? 0FFh0x400_0411
, Not used0x400_0800
, 4, R/W, ?, Undocumented - Internal Memory Control (R/W)0x400_0804
, Not used0x4xx_0800
, 4, R/W, ?, Mirrors of 0x400_0800
(repeated each 64K)Thanks to a bit of madness and a contribution from @aaaaaa123456789 of the gbdev Discord (ax6
on the Discord), it has been decided that, even if the ability to program an arbitrary ISR that's reusable within the crates ecosystem is not currently easy/possible, we can still hand code a basic ISR for just acknowledging a vblank, which allows us to at least use bios::vblank_interrupt_wait
.
This is a stepping stone, not a destination.
But all we have to do is make a static array of u32
values, the raw opcodes of the ARM assembly we want, and then use the pointer to that as our interrupt handling pointer.
They kindly provided the handler code and the u32
values of said code for us:
mov r0, 0x04000002 @e3a00381
add r0, 0x200 @e2800f80
mov r1, -1 @e3e01000
strh r1, [r0] @e1c010b0
bx lr @e12fff1e
GBATEK says that you should only save to SRAM with code executing from WRAM, not with code executing from ROM.
So, we need to describe how to do that.
0x4000060
, 2, R/W, SOUND1CNT_L, Channel 1 Sweep register (NR10)0x4000062
, 2, R/W, SOUND1CNT_H, Channel 1 Duty/Length/Envelope (NR11, NR12)0x4000064
, 2, R/W, SOUND1CNT_X, Channel 1 Frequency/Control (NR13, NR14)0x4000066
, Not used0x4000068
, 2, R/W, SOUND2CNT_L, Channel 2 Duty/Length/Envelope (NR21, NR22)0x400006A
, Not used0x400006C
, 2, R/W, SOUND2CNT_H, Channel 2 Frequency/Control (NR23, NR24)0x400006E
, Not used0x4000070
, 2, R/W, SOUND3CNT_L, Channel 3 Stop/Wave RAM select (NR30)0x4000072
, 2, R/W, SOUND3CNT_H, Channel 3 Length/Volume (NR31, NR32)0x4000074
, 2, R/W, SOUND3CNT_X, Channel 3 Frequency/Control (NR33, NR34)0x4000076
, Not used0x4000078
, 2, R/W, SOUND4CNT_L, Channel 4 Length/Envelope (NR41, NR42)0x400007A
, Not used0x400007C
, 2, R/W, SOUND4CNT_H, Channel 4 Frequency/Control (NR43, NR44)0x400007E
, Not used0x4000080
, 2, R/W, SOUNDCNT_L, Control Stereo/Volume/Enable (NR50, NR51)0x4000082
, 2, R/W, SOUNDCNT_H, Control Mixing/DMA Control0x4000084
, 2, R/W, SOUNDCNT_X, Control Sound on/off (NR52)0x4000086
, Not used0x4000088
, 2, BIOS, SOUNDBIAS, Sound PWM Control0x400008A
, Not used0x4000090
, 2x10, R/W, WAVE_RAM, Channel 3 Wave Pattern RAM (2 banks!!)0x40000A0
, 4, W, FIFO_A, Channel A FIFO, Data 0-30x40000A4
, 4, W, FIFO_B, Channel B FIFO, Data 0-30x40000A8
, Not usednow that rustc itself has a version, our version blocks all builds XD
We should walk the user through how they'd display a string using a bitmap font tilesheet and Mode0
graphics
More than one person has tried to build a "blank" project, which crashes because of missing eh_personality, or tried to use cargo build and had similar trouble.
Perhaps we can work on clarification
Most parts of the Development Setup chapter are pure magic.
We should not attempt to fully document each tool involved. However, we should attempt to document a full list of the tools used and then point people to the appropriate manuals so that they can look into it if they want.
Similarly, we've got a few provided files, and we can explain why they say what they say, and point people to where they'd find out more.
RandomThumb:
bx pc
nop
.arm
RandomARM:
@code here
also investigate umlal
instruction
Apparently we don't really need to specifically use devkitpro's ARM binutils, we can probably just use totally normal GCC binutils for ARMv4TDMI
.
Currently we use devkitpro for the assembler and the linker.
We can't use LLVM's own linker because it has a v5 minimum because it uses the BLX
instruction.
Still, it's worth it to give it a try using more a toolchain that's even more common than we're currently using.
Just a rough outline. The idea is that we'll cover topics by alternating(ish) between graphics and non-graphics topic until all the major stuff that isn't self-explanitory. Things like how particular bios
functions work can often be better described in the crate docs, but the book (hopefully) should give a sense of what you might do with all the bits and bobs available to you.
Ketsuban suggested that we try out cargo-make
https://github.com/sagiegurari/cargo-make
It seems super cool, and if we can replace our build.bat
file with something that'll work more properly on all platforms it'll be good.
From endrift
, referring to the crt0.s
ldr r1, =0x03FFFFFC
str r0, [r1]
can be done in fewer bytes as
mov r1, #0x04000000
str r0, [r1, #-4]
this saves four bytes and one cycle
https://gist.github.com/ketsuban/ec6b72b659221c1f0761a6e966083b41
Not sure where it goes in the TOC, I guess it fits as a non-video section
0x400_0130
, 2, R, KEYINPUT, Key Status0x400_0132
, 2, R/W, KEYCNT, Key Interrupt ControlCPU Control / Reset
0x00
SoftReset0x01
RegisterRamReset0x02
Halt0x03
Stop/Sleep0x04
IntrWait ;DSi7/DSi9: both bugged?0x05
VBlankIntrWait ;DSi7/DSi9: both bugged?Math
0x06
Div0x07
DivArm0x08
Sqrt0x09
ArcTan0x0A
ArcTan2Memory Modification
0x0B
CpuSet0x0C
CpuFastSet0x0D
GetBiosChecksum0x0E
BgAffineSet0x0F
ObjAffineSetDecompression Functions
0x10
BitUnPack0x11
LZ77UnCompReadNormalWrite8bit ;"Wram"0x12
LZ77UnCompReadNormalWrite16bit ;"Vram"0x13
HuffUnCompReadNormal0x14
RLUnCompReadNormalWrite8bit ;"Wram"0x15
RLUnCompReadNormalWrite16bit ;"Vram"0x16
Diff8bitUnFilterWrite8bit ;"Wram"0x17
Diff8bitUnFilterWrite16bit ;"Vram"0x18
Diff16bitUnFilterSound (and Multiboot/HardReset/CustomHalt)
0x19
SoundBias0x1A
SoundDriverInit0x1B
SoundDriverMode0x1C
SoundDriverMain0x1D
SoundDriverVSync0x1E
SoundChannelClear0x1F
MidiKey2Freq0x20
SoundWhatever00x21
SoundWhatever10x22
SoundWhatever20x23
SoundWhatever30x24
SoundWhatever40x25
MultiBoot0x26
HardReset0x27
CustomHalt0x28
SoundDriverVSyncOff0x29
SoundDriverVSyncOn0x2A
SoundGetJumpListTONC and GBATEK explain this concept rather poorly. We will need to ensure that we've got lots of pictures when we explain this feature in the book.
So, if we implement the correct special function, then we can make code like
let a = x / y;
Will suddenly magically work on the GBA.
#[no_mangle] extern "aapcs" fn __aeabi_uidiv(num: u32: denom: u32) -> u32
#[no_mangle] extern "aapcs" fn __aeabi_idiv(num: i32: denom: i32) -> u32
Do we want division to magically work like that?
Personally, I think that division is so damn costly on the GBA that I want it to be called as a special function or even as a macro (which makes it look a little weird) just so that people remember that they're doing a weird and costly operation.
#[no_mangle]
pub unsafe extern "C" fn __clzsi2(mut x: usize) -> usize {
let mut y: usize;
let mut n: usize = 32;
y = x >> 16;
if y != 0 {
n = n - 16;
x = y;
}
y = x >> 8;
if y != 0 {
n = n - 8;
x = y;
}
y = x >> 4;
if y != 0 {
n = n - 4;
x = y;
}
y = x >> 2;
if y != 0 {
n = n - 2;
x = y;
}
y = x >> 1;
if y != 0 {
n - 2
} else {
n - x
}
}
"I just stuck this in a shim.rs file. Eventually with any luck compiler-builtins will provide one which isn't written by me googling for a C implementation and quickly translating it to Rust." -- Ketsuban
It's quite difficult to make any useful abstractions over VRAM for all possible video modes, but I think that we can at least do a good effort if we focus on just one mode at a time.
My first thought is that we can make a sub-module for each display mode and then fill it with display helpers and constants relevant to that mode.
Are there other good options? I also had the idea to try and make TiledGraphics and BitmapGraphics traits that we implement onto empty structs that represent each display mode, but I think even among Tiled and Bitmap modes there's not quite enough similarity to make that very useful.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.