diff options
Diffstat (limited to 'source')
| -rw-r--r-- | source/input.hpp | 45 | ||||
| -rw-r--r-- | source/main.cpp | 57 | ||||
| -rw-r--r-- | source/types.hpp | 18 | ||||
| -rw-r--r-- | source/util.hpp | 191 |
4 files changed, 311 insertions, 0 deletions
diff --git a/source/input.hpp b/source/input.hpp new file mode 100644 index 0000000..2a2a3a2 --- /dev/null +++ b/source/input.hpp @@ -0,0 +1,45 @@ +#include "types.hpp" + + + +typedef u16 KeyFlags; + +enum Key : KeyFlags { + A = 0x0001, + B = 0x0002, + Select = 0x0004, + Start = 0x0008, + Right = 0x0010, + Left = 0x0020, + Up = 0x0040, + Down = 0x0080, + R = 0x0100, + L = 0x0200, +}; + +constexpr KeyFlags KEY_MASK = 0x03FF; + +volatile KeyFlags* const REG_KEYINPUT = reinterpret_cast<volatile KeyFlags*>(0x04000130); + +static inline KeyFlags &keyflags_curr() { + static KeyFlags keybits_curr = 0; + return keybits_curr; +} + +static inline KeyFlags &keyflags_prev() { + static KeyFlags keybits_prev = 0; + return keybits_prev; +} + +static inline void keyflags_poll() { + KeyFlags &prev = keyflags_prev(); + KeyFlags &curr = keyflags_curr(); + + prev = curr; + curr = ~*REG_KEYINPUT & KEY_MASK; +} + +static inline bool key_is_down(Key key) { return keyflags_curr() & key; } +static inline bool key_is_up(Key key) { return ~keyflags_curr() & key; } +static inline bool key_was_down(Key key) { return keyflags_prev() & key; } +static inline bool key_was_up(Key key) { return ~keyflags_prev() & key; } diff --git a/source/main.cpp b/source/main.cpp new file mode 100644 index 0000000..ec6be22 --- /dev/null +++ b/source/main.cpp @@ -0,0 +1,57 @@ +#include "types.hpp" +#include "util.hpp" +#include "input.hpp" + +ScreenEntry *bg0_map = screenblock_mem[28]; + +void bad_vsync() { + while (*REG_VCOUNT >= 160); + while (*REG_VCOUNT < 160); +} + +int main() { + auto bg_flags = BGControlFlags() + .set_charblock_base(0) + .set_screenblock_base(0) + .set_size(BGControlSize::Regular_64x64); + + set_bg_control(0, bg_flags); + set_bg_offsets(0, 0, 0); + + const Tile4 tiles[2] = { + {{0x11111111, 0x01111111, 0x01111111, 0x01111111, 0x01111111, 0x01111111, 0x01111111, 0x00000001}}, + {{0x00000000, 0x00100100, 0x01100110, 0x00011000, 0x00011000, 0x01100110, 0x00100100, 0x00000000}}, + }; + + set_tile(0, 0, tiles[0]); + set_tile(0, 1, tiles[1]); + + set_bg_palette(0, 1, Color::from_rgb(31, 0, 0)); + set_bg_palette(1, 1, Color::from_rgb(31, 0, 0)); + set_bg_palette(2, 1, Color::from_rgb(31, 0, 0)); + set_bg_palette(3, 1, Color::from_rgb(31, 0, 0)); + + ScreenEntry *screen_entry_ptr = bg0_map; + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 32*32; j++) { + *screen_entry_ptr++ = ScreenEntry().set_palette_bank(i); + } + } + + set_display_control(Mode0, BG0); + + s16 x = 0, y = 0; + while (1) { + bad_vsync(); + keyflags_poll(); + + if (key_is_down(Key::Left)) x -= 1; + if (key_is_down(Key::Right)) x += 1; + if (key_is_down(Key::Up)) y -= 1; + if (key_is_down(Key::Down)) y += 1; + + set_bg_offsets(0, x, y); + } + + return 0; +} diff --git a/source/types.hpp b/source/types.hpp new file mode 100644 index 0000000..222b11c --- /dev/null +++ b/source/types.hpp @@ -0,0 +1,18 @@ +#ifndef TYPES_HPP +#define TYPES_HPP + +typedef signed char s8; +typedef signed short s16; +typedef signed int s32; + +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned int u32; + +typedef volatile unsigned char vu8; +typedef volatile unsigned short vu16; +typedef volatile unsigned int vu32; + +typedef u16 color_t; + +#endif diff --git a/source/util.hpp b/source/util.hpp new file mode 100644 index 0000000..7b39376 --- /dev/null +++ b/source/util.hpp @@ -0,0 +1,191 @@ +#ifndef UTIL_HPP +#define UTIL_HPP + +#include "types.hpp" +#include <assert.h> +#include <type_traits> + +constexpr u32 SCREEN_WIDTH = 240; +constexpr u32 SCREEN_HEIGHT = 160; + +vu16* const REG_VCOUNT = reinterpret_cast<vu16*>(0x04000006); + +enum DisplayControlMode : u16 { + Mode0 = 0x0000, + Mode1 = 0x0001, + Mode2 = 0x0002, + Mode3 = 0x0003, + Mode4 = 0x0004, + Mode5 = 0x0005, +}; + +enum DisplayControlLayer : u16 { + BG0 = 0x0100, + BG1 = 0x0200, + BG2 = 0x0400, + BG3 = 0x0800, + BG4 = 0x1000, +}; + +typedef u16 DisplayControlFlags; + +constexpr DisplayControlFlags operator|(DisplayControlMode mode, DisplayControlLayer layer) { + return static_cast<DisplayControlFlags>(static_cast<u16>(mode) | static_cast<u16>(layer)); +} + +static inline void set_display_control(DisplayControlMode mode, DisplayControlLayer layer) { + static volatile DisplayControlFlags* const display_control = reinterpret_cast<DisplayControlFlags*>(0x04000000); + *display_control = mode | layer; +} + +enum BGControlColorMode : u16 { + Mode_4bpp = 0x0000, + Mode_8bpp = 0x0080, +}; + +enum BGControlSize : u16 { + Regular_32x32 = 0x0000, + Regular_64x32 = 0x4000, + Regular_32x64 = 0x8000, + Regular_64x64 = 0xc000, + Affine_16x16 = 0x0000, + Affine_32x32 = 0x4000, + Affine_64x64 = 0x8000, + Affine_128x128 = 0xc000, +}; + +struct BGControlFlags { + u16 flags; + + constexpr BGControlFlags() : flags(0) {} + + constexpr BGControlFlags &set_priority(u16 priority) { + assert(priority < 4); + this->flags = (this->flags & 0xfffc) | priority; + return *this; + } + + constexpr BGControlFlags &set_charblock_base(u16 block) { + assert(block < 4); + this->flags = (this->flags & 0xfff3) | (block << 2); + return *this; + } + + constexpr BGControlFlags &set_mosaic(u16 enabled) { + this->flags = (this->flags & 0xffbf) | (!!enabled << 6); + return *this; + } + + constexpr BGControlFlags &set_color_mode(BGControlColorMode mode) { + this->flags = (this->flags & 0xff7f) | mode; + return *this; + } + + constexpr BGControlFlags &set_screenblock_base(u16 block) { + assert(block < 32); + this->flags = (this->flags & 0xe0ff) | (block << 8); + return *this; + } + + constexpr BGControlFlags &set_affine_wrapping(u16 enabled) { + this->flags = (this->flags & 0xdfff) | (!!enabled << 13); + return *this; + } + + constexpr BGControlFlags &set_size(BGControlSize size) { + this->flags = (this->flags & 0x3fff) | size; + return *this; + } + + constexpr operator u16() const { return this->flags; } +}; + +static inline void set_bg_control(u16 bg, BGControlFlags flags) { + assert(bg < 4); + + vu16* const reg = reinterpret_cast<vu16*>(0x04000008 + 2*bg); + *reg = flags; +} + +static inline void set_bg_offsets(u16 bg, u16 h_offset, u16 v_offset) { + vu16* const h_reg = reinterpret_cast<vu16*>(0x04000010 + 4*bg); + vu16* const v_reg = reinterpret_cast<vu16*>(0x04000012 + 4*bg); + + *h_reg = h_offset; + *v_reg = v_offset; +} + +struct Color { + u16 data; + + static constexpr Color from_rgb(u16 r, u16 g, u16 b) { + assert(r < 32 && g < 32 && b < 32); + return Color { .data = u16(r | (g << 5) | (b << 10)) }; + } +}; + +typedef Color PaletteBank[16]; + +struct Tile4 { u32 data[8]; }; +typedef Tile4 CharBlock4[512]; + +template <typename T> +static inline void volatile_copy(volatile T* dst, const T* src) { + using U = std::conditional_t<(sizeof(T) % sizeof(u32) == 0) && (alignof(T) % alignof(u32) == 0), u32, u16>; + static_assert(sizeof(T) % sizeof(U) == 0); + static_assert(alignof(T) % alignof(U) == 0); + auto *d = reinterpret_cast<volatile U*>(dst); + auto *s = reinterpret_cast<const U*>(src); + for (unsigned i = 0; i < sizeof(T) / sizeof(U); i++) { + d[i] = s[i]; + } +} + +static inline void set_tile(u16 block, u16 index, const Tile4 &tile) { + // TODO bounds check + volatile CharBlock4 *const blocks = reinterpret_cast<volatile CharBlock4*>(0x06000000); + volatile_copy(&blocks[block][index], &tile); +} + +static inline void set_bg_palette(u32 bank, u32 index, const Color &color) { + volatile PaletteBank *const banks = reinterpret_cast<volatile PaletteBank*>(0x05000000); + volatile_copy(&banks[bank][index], &color); +} + +// pair of screen entry bytes +struct ScreenEntry { + u16 data; + + constexpr ScreenEntry() : data(0) {} + constexpr ScreenEntry &set_tile_index(u16 tid) { + assert(tid < 1024); + this->data = (this->data & ~0x03ff) | tid; + return *this; + } + + constexpr ScreenEntry &set_hflip(u16 flip) { + this->data = (this->data & ~0x0400) | (!!flip << 10); + return *this; + } + + constexpr ScreenEntry &set_vflip(u16 flip) { + this->data = (this->data & ~0x0800) | (!!flip << 11); + return *this; + } + + constexpr ScreenEntry &set_palette_bank(u16 bank) { + assert(bank < 16); + this->data = (this->data & ~0xf000) | (bank << 12); + return *this; + } + + constexpr operator u16() const { return this->data; } +}; + +typedef ScreenEntry ScreenBlock[1024]; + +CharBlock4 *const tile4_mem = reinterpret_cast<CharBlock4*>(0x06000000); +PaletteBank *const palette_bg_bank = reinterpret_cast<PaletteBank*>(0x05000000); +ScreenBlock *const screenblock_mem = reinterpret_cast<ScreenBlock*>(0x06000000); + +#endif |
