nes_ppu.h 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. /*
  2. * MIT License
  3. *
  4. * Copyright (c) 2022 Dozingfiretruck
  5. *
  6. * Permission is hereby granted, free of charge, to any person obtaining a copy
  7. * of this software and associated documentation files (the "Software"), to deal
  8. * in the Software without restriction, including without limitation the rights
  9. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10. * copies of the Software, and to permit persons to whom the Software is
  11. * furnished to do so, subject to the following conditions:
  12. *
  13. * The above copyright notice and this permission notice shall be included in all
  14. * copies or substantial portions of the Software.
  15. *
  16. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  19. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  22. * SOFTWARE.
  23. */
  24. #ifndef _NES_PPU_
  25. #define _NES_PPU_
  26. #include "nes_conf.h"
  27. #ifdef __cplusplus
  28. extern "C" {
  29. #endif
  30. #define NES_PPU_VRAM_SIZE 0x1000 /* 4KB */
  31. struct nes;
  32. typedef struct nes nes_t;
  33. // https://www.nesdev.org/wiki/PPU_OAM
  34. typedef struct{
  35. uint8_t y; /* Y position of top of sprite */
  36. union {
  37. struct {
  38. uint8_t pattern_8x16:1; /* Bank ($0000 or $1000) of tiles */
  39. uint8_t tile_index_8x16 :7; /* Tile number of top of sprite (0 to 254; bottom half gets the next tile) */
  40. };
  41. uint8_t tile_index_number; /* Tile index number */
  42. };
  43. union {
  44. struct {
  45. uint8_t sprite_palette:2; /* Palette (4 to 7) of sprite */
  46. uint8_t :3; /* nimplemented (read 0) */
  47. uint8_t priority :1; /* Priority (0: in front of background; 1: behind background) */
  48. uint8_t flip_h :1; /* Flip sprite horizontally */
  49. uint8_t flip_v :1; /* Flip sprite vertically */
  50. };
  51. uint8_t attributes; /* Attributes */
  52. };
  53. uint8_t x; /* X position of left side of sprite. */
  54. } sprite_info_t;
  55. // https://www.nesdev.org/wiki/PPU_registers
  56. typedef struct nes_ppu{
  57. union {
  58. struct {
  59. uint8_t ppu_vram0[NES_PPU_VRAM_SIZE / 4];
  60. uint8_t ppu_vram1[NES_PPU_VRAM_SIZE / 4];
  61. uint8_t ppu_vram2[NES_PPU_VRAM_SIZE / 4];
  62. uint8_t ppu_vram3[NES_PPU_VRAM_SIZE / 4];
  63. };
  64. uint8_t ppu_vram[NES_PPU_VRAM_SIZE];
  65. };
  66. union {
  67. struct {
  68. uint8_t CTRL_N:2; /* Base nametable address (0 = $2000; 1 = $2400; 2 = $2800; 3 = $2C00) */
  69. uint8_t CTRL_I:1; /* VRAM address increment per CPU read/write of PPUDATA (0: add 1, going across; 1: add 32, going down) */
  70. uint8_t CTRL_S:1; /* Sprite pattern table address for 8x8 sprites (0: $0000; 1: $1000; ignored in 8x16 mode) */
  71. uint8_t CTRL_B:1; /* Background pattern table address (0: $0000; 1: $1000) */
  72. uint8_t CTRL_H:1; /* Sprite size (0: 8x8 pixels; 1: 8x16 pixels – see PPU OAM#Byte 1) */
  73. uint8_t CTRL_P:1; /* (0: read backdrop from EXT pins; 1: output color on EXT pins) */
  74. uint8_t CTRL_V:1; /* Generate an NMI at the start of the vertical blanking interval (0: off; 1: on) */
  75. };
  76. uint8_t ppu_ctrl;
  77. };
  78. union {
  79. struct {
  80. uint8_t MASK_Gr:1; /* Greyscale (0: normal color, 1: produce a greyscale display) */
  81. uint8_t MASK_m:1; /* 1: Show background in leftmost 8 pixels of screen, 0: Hide */
  82. uint8_t MASK_M:1; /* 1: Show sprites in leftmost 8 pixels of screen, 0: Hide */
  83. uint8_t MASK_b:1; /* 1: Show background */
  84. uint8_t MASK_s:1; /* 1: Show sprites */
  85. uint8_t MASK_R:1; /* Emphasize red (green on PAL/Dendy) */
  86. uint8_t MASK_G:1; /* Emphasize green (red on PAL/Dendy) */
  87. uint8_t MASK_B:1; /* Emphasize blue */
  88. };
  89. uint8_t ppu_mask;
  90. };
  91. union {
  92. struct {
  93. uint8_t :4;
  94. uint8_t STATUS_F:1; /* VRAM write flag: 0 = write valid, 1 = write ignored */
  95. uint8_t STATUS_O:1; /* Sprite overflow. The intent was for this flag to be set
  96. whenever more than eight sprites appear on a scanline, but a
  97. hardware bug causes the actual behavior to be more complicated
  98. and generate false positives as well as false negatives; see
  99. PPU sprite evaluation. This flag is set during sprite
  100. evaluation and cleared at dot 1 (the second dot) of the
  101. pre-render line. */
  102. uint8_t STATUS_S:1; /* Sprite 0 Hit. Set when a nonzero pixel of sprite 0 overlaps
  103. a nonzero background pixel; cleared at dot 1 of the pre-render
  104. line. Used for raster timing. */
  105. uint8_t STATUS_V:1; /* Vertical blank has started (0: not in vblank; 1: in vblank).
  106. Set at dot 1 of line 241 (the line *after* the post-render
  107. line); cleared after reading $2002 and at dot 1 of the
  108. pre-render line. */
  109. };
  110. uint8_t ppu_status;
  111. };
  112. union {
  113. struct {
  114. uint8_t* pattern_table[8];
  115. uint8_t* name_table[4];
  116. };
  117. uint8_t* chr_banks[16]; /* 16k chr_banks,without background_palette and sprite_palette
  118. 0 - 3 pattern_table_0 4k
  119. 4 - 7 pattern_table_1 4k
  120. 8 name_table_0 1k
  121. 9 name_table_1 1k
  122. 10 name_table_2 1k
  123. 11 name_table_3 1k
  124. 12-15 mirrors */
  125. };
  126. union {
  127. struct{ // Scroll
  128. uint16_t coarse_x : 5;
  129. uint16_t coarse_y : 5;
  130. uint16_t nametable : 2;
  131. uint16_t fine_y : 3;
  132. uint16_t : 1;
  133. }v;
  134. uint16_t v_reg; /* Current VRAM address (15 bits) */
  135. };
  136. union {
  137. struct{ // Scroll
  138. uint16_t coarse_x : 5;
  139. uint16_t coarse_y : 5;
  140. uint16_t nametable : 2;
  141. uint16_t fine_y : 3;
  142. uint16_t : 1;
  143. }t;
  144. uint16_t t_reg; /* Temporary VRAM address (15 bits); can also be thought of as the address of the top left onscreen tile. */
  145. };
  146. struct {
  147. uint8_t x:3; /* Fine X scroll (3 bits) */
  148. uint8_t w:1; /* First or second write toggle (1 bit) */
  149. uint8_t :4;// 可利用做xxx标志位
  150. };
  151. uint8_t oam_addr; /* OAM read/write address */
  152. union {
  153. sprite_info_t sprite_info[0x100 / 4];
  154. uint8_t oam_data[0x100]; /* OAM data read/write
  155. The OAM (Object Attribute Memory) is internal memory inside the PPU that contains a display list of up to 64 sprites,
  156. where each sprite's information occupies 4 bytes.*/
  157. };
  158. uint8_t buffer; /* PPU internal buffer */
  159. uint8_t palette_indexes[0x20]; /* $3F00-$3F1F Palette RAM indexes */
  160. union {
  161. struct {
  162. nes_color_t background_palette[0x10];
  163. nes_color_t sprite_palette[0x10];
  164. };
  165. nes_color_t palette[0x20];
  166. };
  167. } nes_ppu_t;
  168. void nes_ppu_init(nes_t *nes);
  169. uint8_t nes_read_ppu_register(nes_t *nes,uint16_t address);
  170. void nes_write_ppu_register(nes_t *nes,uint16_t address, uint8_t data);
  171. #ifdef __cplusplus
  172. }
  173. #endif
  174. #endif// _NES_PPU_