Files
gbdk-2020/gbdk-lib/include/nes/hardware.h
Michel Iwaniec 62de8abb87 NES: Add support for various tilemap layout (mirroring) configurations (#783)
* NES: Add support for various tilemap layout (mirroring) configurations

- Introduce platform configuration, mainly to define tilemap layout NES_TILEMAP_[F|H|V|S] in platform_cfg.s
  + Add NES_TILEMAP_S|H|V|F setting for tilemap layout, and hard-code to NES_TILEMAP_S for now
  + Add NES_LOMEM setting to enable current default of using part of stack instead of BSS for attribute shadow buffer
  + Edit Makefile to copy platform_cfg.s (if it exists) to platform directory after build

- Updates to attribute shadow buffer and dirty bits:
  + Add NUM_NT define for number of nametables used by a layout, and AT_SHADOW_WIDTH/_HEIGHT to denote the variable dimensions
  + Add convenience defines NT_2W / NT_2H to quickly test whether tilemap layout is two screens wide / high
  + Define _attribute_shadow and _attribute_row/_column_dirty in terms of NUM_NT
  + Update flush_attributes to support all layouts
  + Update get_bkg_xy_addr / set_bkg_tile_xy to support all layouts
  + Update set_bkg_attribute_xy[_nes16x16] to support all layouts
  + Update set_bkg_attributes[_nes16x16] to support all layouts, and correctly wrap to next AT in both directions
  + Update set_bkg_submap_attributes[_nes16x16] to support all layouts
  + Update set_bkg_submap to support all layouts, and contain common inner subroutine .set_bkg_common
  + Replace set_bkg_tiles with simpler implementation calling .set_bkg_common, and correctly wraps to next NT in both directions
  + Add set_bkg_based_tiles / set_bkg_based_submap implementations using the new common subroutine

- Updates to C include files:
  + Define DEVICE_SCREEN_BUFFER_WIDTH/_HEIGHT based on NES_TILEMAP_ setting, doubling high-level size of WIDTH / HEIGHT conditionally
  + Add typedefs scroll_x_t / scroll_y_t as uint8_t or uint16_t based on NES_TILEMAP_ setting
  + Make move_bkg use scroll_x/y_t typedefs, set 9th scroll bit in shadow_PPUCTRL where needed, and compensate for 239->0 y wrapping

- Updates to examples:
  + Update large_map example to use platform-agnostic settings for scroll wrapping and offset
  + Update rle_map to use a uint16_t for scroll position, to support NES_TILEMAP_H and NES_TILEMAP_F settings
2025-05-19 12:44:45 +01:00

101 lines
2.9 KiB
C

/** @file nes/hardware.h
Defines that let the NES hardware registers be accessed
from C.
*/
#ifndef _HARDWARE_H
#define _HARDWARE_H
#include <types.h>
#define __SHADOW_REG extern volatile uint8_t
#define __REG(addr) volatile __at (addr) uint8_t
__REG(0x2000) PPUCTRL;
#define PPUCTRL_NMI 0b10000000
#define PPUCTRL_SPR_8X8 0b00000000
#define PPUCTRL_SPR_8X16 0b00100000
#define PPUCTRL_BG_CHR 0b00010000
#define PPUCTRL_SPR_CHR 0b00001000
#define PPUCTRL_INC32 0b00000100
__SHADOW_REG shadow_PPUCTRL;
__REG(0x2001) PPUMASK;
#define PPUMASK_BLUE 0b10000000
#define PPUMASK_RED 0b01000000
#define PPUMASK_GREEN 0b00100000
#define PPUMASK_SHOW_SPR 0b00010000
#define PPUMASK_SHOW_BG 0b00001000
#define PPUMASK_SHOW_SPR_LC 0b00000100
#define PPUMASK_SHOW_BG_LC 0b00000010
#define PPUMASK_MONOCHROME 0b00000001
__SHADOW_REG shadow_PPUMASK;
__REG(0x2002) PPUSTATUS;
__REG(0x2003) OAMADDR;
__REG(0x2004) OAMDATA;
__REG(0x2005) PPUSCROLL;
__REG(0x2006) PPUADDR;
__REG(0x2007) PPUDATA;
__REG(0x4014) OAMDMA;
#define DEVICE_SCREEN_X_OFFSET 0
#define DEVICE_SCREEN_Y_OFFSET 0
#define DEVICE_SCREEN_WIDTH 32
#define DEVICE_SCREEN_HEIGHT 30
#if defined(NES_TILEMAP_F)
// Full tilemap
#define DEVICE_SCREEN_BUFFER_WIDTH 64
#define DEVICE_SCREEN_BUFFER_HEIGHT 60
typedef uint16_t scroll_x_t;
typedef uint16_t scroll_y_t;
#elif defined(NES_TILEMAP_H)
// Horizontally arranged tilemap
#define DEVICE_SCREEN_BUFFER_WIDTH 64
#define DEVICE_SCREEN_BUFFER_HEIGHT 30
typedef uint16_t scroll_x_t;
typedef uint8_t scroll_y_t;
#elif defined(NES_TILEMAP_V)
// Vertically arranged tilemap
#define DEVICE_SCREEN_BUFFER_WIDTH 32
#define DEVICE_SCREEN_BUFFER_HEIGHT 60
typedef uint8_t scroll_x_t;
typedef uint16_t scroll_y_t;
#else
// Single-screen tilemap
#define DEVICE_SCREEN_BUFFER_WIDTH 32
#define DEVICE_SCREEN_BUFFER_HEIGHT 30
typedef uint8_t scroll_x_t;
typedef uint8_t scroll_y_t;
#endif
#define DEVICE_SCREEN_MAP_ENTRY_SIZE 1
#define DEVICE_SPRITE_PX_OFFSET_X 0
#define DEVICE_SPRITE_PX_OFFSET_Y -1
#define DEVICE_WINDOW_PX_OFFSET_X 0
#define DEVICE_WINDOW_PX_OFFSET_Y 0
#define DEVICE_SCREEN_PX_WIDTH (DEVICE_SCREEN_WIDTH * 8)
#define DEVICE_SCREEN_PX_HEIGHT (DEVICE_SCREEN_HEIGHT * 8)
// Scrolling coordinates (will be written to PPUSCROLL at end-of-vblank by NMI handler)
__SHADOW_REG bkg_scroll_x;
__SHADOW_REG bkg_scroll_y;
// LCD scanline - a software-driven version of GB's incrasing 'LY' scanline counter
__SHADOW_REG _lcd_scanline;
extern volatile UBYTE TIMA_REG;
extern volatile UBYTE TMA_REG;
extern volatile UBYTE TAC_REG;
// Compatibility defines for GB LY / LYC registers, to allow easier LCD ISR porting
#define SCY_REG bkg_scroll_y /**< Scroll Y */
#define rSCY SCY_REG
#define SCX_REG bkg_scroll_x /**< Scroll X */
#define rSCX SCX_REG
#define LY_REG _lcd_scanline /**< LCDC Y-coordinate */
#define rLY LY_REG
#define LYC_REG _lcd_scanline /**< LY compare */
#define rLYC LYC_REG
#endif