From 24887f28c3eb6d67a7c1a0803520b3fb728ee4f3 Mon Sep 17 00:00:00 2001 From: Bad Diode Date: Mon, 26 Apr 2021 11:11:36 +0200 Subject: Move code to relevant files for organization --- src/common.h | 281 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 281 insertions(+) create mode 100644 src/common.h (limited to 'src/common.h') diff --git a/src/common.h b/src/common.h new file mode 100644 index 0000000..35b4619 --- /dev/null +++ b/src/common.h @@ -0,0 +1,281 @@ +#ifndef GBAEXP_COMMON_H +#define GBAEXP_COMMON_H + +#include "shorthand.h" + +// +// Memory sections. +// + +// Defines for the different memory sections in the GBA. +#define MEM_SROM 0x00000000 +#define MEM_EW 0x02000000 +#define MEM_IW 0x03000000 +#define MEM_IO 0x04000000 +#define MEM_PAL 0x05000000 +#define MEM_VRAM 0x06000000 +#define MEM_OAM 0x07000000 +#define MEM_PAK 0x08000000 +#define MEM_CART 0x0E000000 + +// +// Display modes. +// + +// Display registers. +#define DISP_CTRL *((vu32*)(MEM_IO + 0x0000)) +#define DISP_STATUS *((vu16*)(MEM_IO + 0x0004)) +#define DISP_VCOUNT *((vu16*)(MEM_IO + 0x0006)) + +// The first three bits in the DISP_CTRL are used to control the video mode. +#define DISP_MODE_0 0x0000 +#define DISP_MODE_1 0x0001 +#define DISP_MODE_2 0x0002 +#define DISP_MODE_3 0x0003 +#define DISP_MODE_4 0x0004 +#define DISP_MODE_5 0x0005 +#define DISP_GB (1 << 3) +#define DISP_PAGE (1 << 4) +#define DISP_OAM_HBLANK (1 << 5) +#define DISP_OBJ_1D (1 << 6) +#define DISP_BLANK (1 << 7) +#define DISP_BG_0 (1 << 8) +#define DISP_BG_1 (1 << 9) +#define DISP_BG_2 (1 << 10) +#define DISP_BG_3 (1 << 11) +#define DISP_OBJ (1 << 12) +#define DISP_ENABLE_SPRITES DISP_OBJ | DISP_OBJ_1D + +// Registers to control of BG layers. +#define BG_CTRL_0 *((vu16*)(0x04000008 + 0x0002 * 0)) +#define BG_CTRL_1 *((vu16*)(0x04000008 + 0x0002 * 1)) +#define BG_CTRL_2 *((vu16*)(0x04000008 + 0x0002 * 2)) +#define BG_CTRL_3 *((vu16*)(0x04000008 + 0x0002 * 3)) + +// Bits to control the background. +#define BG_PRIORITY_0 0x0 +#define BG_PRIORITY_1 0x1 +#define BG_PRIORITY_2 0x2 +#define BG_PRIORITY_3 0x3 +#define BG_CHARBLOCK(N) ((N) << 2) +#define BG_MOSAIC (1 << 6) +#define BG_HIGH_COLOR (1 << 7) +#define BG_SCREENBLOCK(N) ((N) << 8) +#define BG_AFFINE (1 << 0xD) +#define BG_SIZE(N) ((N) << 0xE) + +// BG registers for horizontal displacement. +#define BG_H_SCROLL_0 *((vu16*)(0x04000010 + 0x0004 * 0)) +#define BG_H_SCROLL_1 *((vu16*)(0x04000010 + 0x0004 * 1)) +#define BG_H_SCROLL_2 *((vu16*)(0x04000010 + 0x0004 * 2)) +#define BG_H_SCROLL_3 *((vu16*)(0x04000010 + 0x0004 * 3)) + +// BG registers for vertical displacement. +#define BG_V_SCROLL_0 *((vu16*)(0x04000012 + 0x0004 * 0)) +#define BG_V_SCROLL_1 *((vu16*)(0x04000012 + 0x0004 * 1)) +#define BG_V_SCROLL_2 *((vu16*)(0x04000012 + 0x0004 * 2)) +#define BG_V_SCROLL_3 *((vu16*)(0x04000012 + 0x0004 * 3)) + +// Screen settings. +#define SCREEN_WIDTH 240 +#define SCREEN_HEIGHT 160 + +// The GBA in mode 3 expects rbg15 colors in the VRAM, where each component +// (RGB) have a 0--31 range. For example, pure red would be rgb15(31, 0, 0). +typedef u16 Color; + +// +// Tile memory access. +// + +// NOTE: Only defining 4bpp tiles for now. +typedef struct Tile { + u32 data[8]; +} Tile; + +typedef Tile TileBlock[512]; +#define TILE_MEM ((TileBlock*) MEM_VRAM) + +typedef u16 ScreenBlock[1024]; +#define SCREENBLOCK_MEM ((ScreenBlock*)MEM_VRAM) + +// We can treat the screen as a HxW matrix. With the following macro we can +// write a pixel to the screen at the (x, y) position using: +// +// FRAMEBUFFER[y][x] = color; +// +typedef Color Scanline[SCREEN_WIDTH]; +#define FRAMEBUFFER ((Scanline*)MEM_VRAM) +#define SCREEN_BUFFER ((u16*) MEM_VRAM) +#define PAL_BUFFER_BG ((u16*) MEM_PAL) +#define PAL_BUFFER_SPRITES ((u16*) 0x05000200) + +// +// Colors. +// + +static inline Color +rgb15(u32 red, u32 green, u32 blue ) { + return (blue << 10) | (green << 5) | red; +} + +#define COLOR_RED rgb15(31, 0, 12) +#define COLOR_BLUE rgb15(2, 15, 30) +#define COLOR_CYAN rgb15(0, 30, 30) +#define COLOR_GREY rgb15(4, 4, 4) +#define COLOR_BLACK rgb15(0, 0, 0) +#define COLOR_WHITE rgb15(28, 28, 28) + +// +// Sprites. +// + +// Using macros instead of aligned structs for setting up OBJ attributes and +// affine parameters. +// TODO: Benchmark if this would be slower or the same that TONC's +// implementation. +#define OBJ_ATTR_0(N) *((vu16*)(MEM_OAM + 0 + 8 * (N))) +#define OBJ_ATTR_1(N) *((vu16*)(MEM_OAM + 2 + 8 * (N))) +#define OBJ_ATTR_2(N) *((vu16*)(MEM_OAM + 4 + 8 * (N))) +#define OBJ_AFFINE_PA(N) *((vs16*)(MEM_OAM + 6 + 8 * 0 + 8 * 4 * (N))) +#define OBJ_AFFINE_PB(N) *((vs16*)(MEM_OAM + 6 + 8 * 1 + 8 * 4 * (N))) +#define OBJ_AFFINE_PC(N) *((vs16*)(MEM_OAM + 6 + 8 * 2 + 8 * 4 * (N))) +#define OBJ_AFFINE_PD(N) *((vs16*)(MEM_OAM + 6 + 8 * 3 + 8 * 4 * (N))) + +// OBJ_ATTR_0 parameters +#define OBJ_Y_COORD(N) ((N) & 0xFF) +#define OBJ_NORMAL (0x00 << 0x8) +#define OBJ_AFFINE (0x01 << 0x8) +#define OBJ_HIDDEN (0x02 << 0x8) +#define OBJ_AFFINE_2X (0x03 << 0x8) +#define OBJ_ALPHA_BLEND (0x01 << 0xA) +#define OBJ_WINDOW (0x02 << 0xA) +#define OBJ_SHAPE_SQUARE (0x00 << 0xE) +#define OBJ_SHAPE_WIDE (0x01 << 0xE) +#define OBJ_SHAPE_TALL (0x02 << 0xE) + +// OBJ_ATTR_1 parameters +#define OBJ_X_COORD(N) ((N) & 0x1FF) +#define OBJ_AFFINE_IDX(N) ((N) << 0x9) +#define OBJ_H_FLIP (0x01 << 0xC) +#define OBJ_V_FLIP (0x01 << 0xD) +#define OBJ_SIZE_SMALL (0x00 << 0xE) +#define OBJ_SIZE_MID (0x01 << 0xE) +#define OBJ_SIZE_BIG (0x02 << 0xE) +#define OBJ_SIZE_HUGE (0x03 << 0xE) + +// OBJ_ATTR_2 parameters +#define OBJ_TILE_INDEX(N) ((N) & 0x3FF) +#define OBJ_PRIORITY(N) ((N) << 0xA) +#define OBJ_PAL_BANK(N) ((N) << 0xC) + +static inline void +wait_vsync(void) { + while(DISP_VCOUNT >= 160); + while(DISP_VCOUNT < 160); +} + +// +// Mode 4 page flipping +// + +static inline void +flip_page(void) { + DISP_CTRL ^= DISP_PAGE; +} + +#define SCREEN_PAGE_1 ((vu16*) MEM_VRAM) +#define SCREEN_PAGE_2 ((vu16*) (MEM_VRAM + 0xa000)) + +// +// Profiling. +// + +#define TIMER_DATA_0 *((vu16*) (0x04000100 + 0x04 * 0)) +#define TIMER_DATA_1 *((vu16*) (0x04000100 + 0x04 * 1)) +#define TIMER_DATA_2 *((vu16*) (0x04000100 + 0x04 * 2)) +#define TIMER_DATA_3 *((vu16*) (0x04000100 + 0x04 * 3)) +#define TIMER_CTRL_0 *((vu16*) (0x04000102 + 0x04 * 0)) +#define TIMER_CTRL_1 *((vu16*) (0x04000102 + 0x04 * 1)) +#define TIMER_CTRL_2 *((vu16*) (0x04000102 + 0x04 * 2)) +#define TIMER_CTRL_3 *((vu16*) (0x04000102 + 0x04 * 3)) + +// Timer control bits. +#define TIMER_CTRL_FREQ_0 0 +#define TIMER_CTRL_FREQ_1 1 +#define TIMER_CTRL_FREQ_2 2 +#define TIMER_CTRL_FREQ_3 3 +#define TIMER_CTRL_CASCADE (1 << 2) +#define TIMER_CTRL_IRQ (1 << 6) +#define TIMER_CTRL_ENABLE (1 << 7) + +// We use timers 2 and 3 to count the number of cycles since the profile_start +// functions is called. Don't use if the code we are trying to profile make use +// of these timers. +static inline +void profile_start(void) { + TIMER_DATA_2 = 0; + TIMER_DATA_3 = 0; + TIMER_CTRL_2 = 0; + TIMER_CTRL_3 = 0; + TIMER_CTRL_3 = TIMER_CTRL_ENABLE | TIMER_CTRL_CASCADE; + TIMER_CTRL_2 = TIMER_CTRL_ENABLE; +} + +static inline +u32 profile_stop(void) { + TIMER_CTRL_2 = 0; + return (TIMER_DATA_3 << 16) | TIMER_DATA_2; +} + +// +// Input handling. +// + +// Memory address for key input register +#define KEY_INPUTS *((vu16*) 0x04000130) + +// Alias for key pressing bits. +#define KEY_A (1 << 0) +#define KEY_B (1 << 1) +#define KEY_SELECT (1 << 2) +#define KEY_START (1 << 3) +#define KEY_RIGHT (1 << 4) +#define KEY_LEFT (1 << 5) +#define KEY_UP (1 << 6) +#define KEY_DOWN (1 << 7) +#define KEY_R (1 << 8) +#define KEY_L (1 << 9) + +#define KEY_MASK 0x03FF + +// Saving the previous and current key states as globals for now. +static u16 key_curr = 0; +static u16 key_prev = 0; + +static inline void +poll_keys(void) { + key_prev = key_curr; + key_curr = ~KEY_INPUTS & KEY_MASK; +} + +// Returns true if the given key has been pressed at time of calling and was not +// pressed since the previous call. For example, if a key is being held, this +// function will return `true` only on the frame where the key initially +// activated. +static inline u32 +key_pressed(u32 key) { + return (key_curr & key) & ~(key_prev & key); +} + +// Check if the given key is pressed and has been since at least one frame. +static inline u32 +key_hold(u32 key) { + return (key_curr & key) & key_prev & key; +} + +// Check if the given key/button is currently pressed. +#define KEY_PRESSED(key) (~(KEY_INPUTS) & key) + + +#endif // GBAEXP_COMMON_H -- cgit v1.2.1