memory ****** This module exposes waitstate and DMA control registers, constants for relocating code/data, as well as access to ROM and SRAM as arrays. .. ----------------------------- Section Constants ================= These are to be used with the `codegenDecl `_ pragma to place your variables and procedures into certain regions of memory. They cannot be used for local variables, as those are always on the stack which is in IWRAM. **Example:** .. code-block:: nim # Define an array which is statically allocated in EWRAM. var collisionGrid {.codegenDecl: DataInEwram.}: array[2048, uint16] .. autonim:: private.gba.memory.DataInIwram .. autonim:: private.gba.memory.DataInEwram .. autonim:: private.gba.memory.ArmCodeInIwram .. autonim:: private.gba.memory.ThumbCodeInEwram .. tip:: You may wish create shorthands for these in your project, like so: .. code-block:: nim {.pragma: ewdata, codegenDecl: DataInEwram.} {.pragma: iwdata, codegenDecl: DataInIwram.} {.pragma: ewcode, codegenDecl: ThumbCodeInEwram.} {.pragma: iwcode, codegenDecl: ArmCodeInIwram.} You could save this in a *prelude.nim* file along with commonly-used imports which could then be `included `__ at the start of each module in your game. ----------------------------- Memory-mapped arrays ==================== .. autonim:: private.memmap.romMem .. autonim:: private.memmap.sramMem ----------------------------- Waitstate Control ================= .. autonim:: private.gba.memory.waitcnt .. autonim:: memory.WaitCnt .. autonim:: memory.WsSram .. autonim:: memory.WsRom0 .. note:: On Nim 1.6 and later, you can omit the enum prefixes as long as you enable `overloadable enums `_. In other words, you can write `N3_S1` instead of `WsRom0.N3_S1`. .. autonim:: memory.WsRom1 .. autonim:: memory.WsRom2 .. autonim:: memory.WsPhi ----------------------------- Direct Memory Access ==================== Direct Memory Access (DMA) is a hardware feature that allows the GBA to quickly copy data from one location to another at a given moment. Channels 0 and 1 are required for audio (:doc:`maxmod` will take care of these), while 2 and 3 may be used for anything you like. Note that DMA comes with some caveats that make it dangerous to use (and it's not much faster than an optimised copy routine like :xref:`memcpy32` anyways), so I wouldn't recommend it for general purposes. DMA can be applied on HBlank (known as HDMA) for some neat scanline-based effects. The HBlank tnterrupt could also be used for such effects, but HDMA **Example:** .. code-block:: nim # Create a table of horizontal scroll offsets: var hofsTable: array[ScreenHeight, int16] # Populate the table with a sine curve: for i in 0 ..< ScreenHeight: hofsTable[i] = (luSin(i * 100) shr 13).int16 proc onVBlank() = # Cancel previous DMA. dmach[3].stop() # Setup new DMA: Each scanline, copy a subsequent value from the table # into BG3's horizontal scroll register. dmach[3].start( dst = addr bgofs[3].x, src = addr hofsTable[0], count = 1, dstMode = Fix, srcMode = Inc, repeat = true, size = Halfwords, time = AtHBlank, ) .. danger:: If you cancel a DMA transfer within a few CPU cycles of it starting internally, the whole GBA will **lock up** and possibly trash *all* the memory (including save data!) For this reason, you should make sure to stop DMA at a safe moment when no transfer is about to occur, for example HDMA could be cancelled at the start of your VBlank handler. .. autonim:: private.gba.memory.dmach .. autonim:: memory.DmaChannel .. autonim:: memory.DmaCnt .. autonim:: memory.DmaDstMode .. autonim:: memory.DmaSrcMode .. autonim:: memory.DmaSize .. autonim:: memory.DmaTime .. autonim:: private.gba.memory.start .. autonim:: private.gba.memory.stop ----------------------------- Procedures ========== .. autonim:: memory.slowGamePak