test
Dependencies: SDFileSystem mbed-dev
Fork of Nucleo_Ex06_EMU by
pNesX.cpp@4:53ef91c87d74, 2017-05-27 (annotated)
- Committer:
- charliex
- Date:
- Sat May 27 02:17:37 2017 +0000
- Revision:
- 4:53ef91c87d74
test
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
charliex | 4:53ef91c87d74 | 1 | /*===================================================================*/ |
charliex | 4:53ef91c87d74 | 2 | /* */ |
charliex | 4:53ef91c87d74 | 3 | /* pNesX.cpp : NES Emulator for PSX */ |
charliex | 4:53ef91c87d74 | 4 | /* */ |
charliex | 4:53ef91c87d74 | 5 | /* 1999/11/03 Racoon New preparation */ |
charliex | 4:53ef91c87d74 | 6 | /* 2016/ 1/20 Racoon Some optimization. */ |
charliex | 4:53ef91c87d74 | 7 | /* */ |
charliex | 4:53ef91c87d74 | 8 | /*===================================================================*/ |
charliex | 4:53ef91c87d74 | 9 | |
charliex | 4:53ef91c87d74 | 10 | /*------------------------------------------------------------------- |
charliex | 4:53ef91c87d74 | 11 | * File List : |
charliex | 4:53ef91c87d74 | 12 | * |
charliex | 4:53ef91c87d74 | 13 | * [NES Hardware] |
charliex | 4:53ef91c87d74 | 14 | * pNesX.cpp |
charliex | 4:53ef91c87d74 | 15 | * pNesX.h |
charliex | 4:53ef91c87d74 | 16 | * K6502_rw.h |
charliex | 4:53ef91c87d74 | 17 | * pNesX_Apu.cpp (Added) |
charliex | 4:53ef91c87d74 | 18 | * |
charliex | 4:53ef91c87d74 | 19 | * [Mapper function] |
charliex | 4:53ef91c87d74 | 20 | * pNesX_Mapper.cpp |
charliex | 4:53ef91c87d74 | 21 | * pNesX_Mapper.h |
charliex | 4:53ef91c87d74 | 22 | * |
charliex | 4:53ef91c87d74 | 23 | * [The function which depends on a system] |
charliex | 4:53ef91c87d74 | 24 | * pNesX_System_ooo.cpp (ooo is a system name. psx, win, Nucleo...) |
charliex | 4:53ef91c87d74 | 25 | * pNesX_System.h |
charliex | 4:53ef91c87d74 | 26 | * |
charliex | 4:53ef91c87d74 | 27 | * [CPU] |
charliex | 4:53ef91c87d74 | 28 | * K6502.cpp |
charliex | 4:53ef91c87d74 | 29 | * K6502.h |
charliex | 4:53ef91c87d74 | 30 | * |
charliex | 4:53ef91c87d74 | 31 | * [Others] |
charliex | 4:53ef91c87d74 | 32 | * pNesX_Types.h |
charliex | 4:53ef91c87d74 | 33 | * |
charliex | 4:53ef91c87d74 | 34 | --------------------------------------------------------------------*/ |
charliex | 4:53ef91c87d74 | 35 | |
charliex | 4:53ef91c87d74 | 36 | /*-------------------------------------------------------------------*/ |
charliex | 4:53ef91c87d74 | 37 | /* Include files */ |
charliex | 4:53ef91c87d74 | 38 | /*-------------------------------------------------------------------*/ |
charliex | 4:53ef91c87d74 | 39 | |
charliex | 4:53ef91c87d74 | 40 | #include "mbed.h" |
charliex | 4:53ef91c87d74 | 41 | #include "pNesX.h" |
charliex | 4:53ef91c87d74 | 42 | #include "pNesX_System.h" |
charliex | 4:53ef91c87d74 | 43 | #include "pNesX_Mapper.h" |
charliex | 4:53ef91c87d74 | 44 | #include "K6502.h" |
charliex | 4:53ef91c87d74 | 45 | /* |
charliex | 4:53ef91c87d74 | 46 | * Board Resources |
charliex | 4:53ef91c87d74 | 47 | */ |
charliex | 4:53ef91c87d74 | 48 | extern DigitalOut bLED1; |
charliex | 4:53ef91c87d74 | 49 | extern DigitalOut bLED2; |
charliex | 4:53ef91c87d74 | 50 | |
charliex | 4:53ef91c87d74 | 51 | /*-------------------------------------------------------------------*/ |
charliex | 4:53ef91c87d74 | 52 | /* NES resources */ |
charliex | 4:53ef91c87d74 | 53 | /*-------------------------------------------------------------------*/ |
charliex | 4:53ef91c87d74 | 54 | |
charliex | 4:53ef91c87d74 | 55 | /* RAM */ |
charliex | 4:53ef91c87d74 | 56 | BYTE RAM[ RAM_SIZE ]; |
charliex | 4:53ef91c87d74 | 57 | |
charliex | 4:53ef91c87d74 | 58 | /* SRAM */ |
charliex | 4:53ef91c87d74 | 59 | BYTE SRAM[ SRAM_SIZE ]; |
charliex | 4:53ef91c87d74 | 60 | |
charliex | 4:53ef91c87d74 | 61 | /* ROM */ |
charliex | 4:53ef91c87d74 | 62 | BYTE *ROM; |
charliex | 4:53ef91c87d74 | 63 | |
charliex | 4:53ef91c87d74 | 64 | /* ROM BANK ( 8Kb * 4 ) */ |
charliex | 4:53ef91c87d74 | 65 | BYTE *ROMBANK0; |
charliex | 4:53ef91c87d74 | 66 | BYTE *ROMBANK1; |
charliex | 4:53ef91c87d74 | 67 | BYTE *ROMBANK2; |
charliex | 4:53ef91c87d74 | 68 | BYTE *ROMBANK3; |
charliex | 4:53ef91c87d74 | 69 | |
charliex | 4:53ef91c87d74 | 70 | /*-------------------------------------------------------------------*/ |
charliex | 4:53ef91c87d74 | 71 | /* PPU resources */ |
charliex | 4:53ef91c87d74 | 72 | /*-------------------------------------------------------------------*/ |
charliex | 4:53ef91c87d74 | 73 | |
charliex | 4:53ef91c87d74 | 74 | /* PPU RAM */ |
charliex | 4:53ef91c87d74 | 75 | BYTE PPURAM[ PPURAM_SIZE ]; |
charliex | 4:53ef91c87d74 | 76 | |
charliex | 4:53ef91c87d74 | 77 | /* VROM */ |
charliex | 4:53ef91c87d74 | 78 | BYTE *VROM; |
charliex | 4:53ef91c87d74 | 79 | |
charliex | 4:53ef91c87d74 | 80 | /* PPU BANK ( 1Kb * 16 ) */ |
charliex | 4:53ef91c87d74 | 81 | BYTE *PPUBANK[ 16 ]; |
charliex | 4:53ef91c87d74 | 82 | |
charliex | 4:53ef91c87d74 | 83 | /* Sprite RAM */ |
charliex | 4:53ef91c87d74 | 84 | BYTE SPRRAM[ SPRRAM_SIZE ]; |
charliex | 4:53ef91c87d74 | 85 | |
charliex | 4:53ef91c87d74 | 86 | /* PPU Register */ |
charliex | 4:53ef91c87d74 | 87 | BYTE PPU_R0; |
charliex | 4:53ef91c87d74 | 88 | BYTE PPU_R1; |
charliex | 4:53ef91c87d74 | 89 | BYTE PPU_R2; |
charliex | 4:53ef91c87d74 | 90 | BYTE PPU_R3; |
charliex | 4:53ef91c87d74 | 91 | BYTE PPU_R7; |
charliex | 4:53ef91c87d74 | 92 | |
charliex | 4:53ef91c87d74 | 93 | /* Flag for PPU Address and Scroll Latch */ |
charliex | 4:53ef91c87d74 | 94 | BYTE PPU_Latch_Flag; |
charliex | 4:53ef91c87d74 | 95 | |
charliex | 4:53ef91c87d74 | 96 | /* Vertical scroll value */ |
charliex | 4:53ef91c87d74 | 97 | BYTE PPU_Scr_V; |
charliex | 4:53ef91c87d74 | 98 | BYTE PPU_Scr_V_Next; |
charliex | 4:53ef91c87d74 | 99 | BYTE PPU_Scr_V_Byte; |
charliex | 4:53ef91c87d74 | 100 | BYTE PPU_Scr_V_Byte_Next; |
charliex | 4:53ef91c87d74 | 101 | BYTE PPU_Scr_V_Bit; |
charliex | 4:53ef91c87d74 | 102 | BYTE PPU_Scr_V_Bit_Next; |
charliex | 4:53ef91c87d74 | 103 | |
charliex | 4:53ef91c87d74 | 104 | /* Horizontal scroll value */ |
charliex | 4:53ef91c87d74 | 105 | BYTE PPU_Scr_H; |
charliex | 4:53ef91c87d74 | 106 | BYTE PPU_Scr_H_Next; |
charliex | 4:53ef91c87d74 | 107 | BYTE PPU_Scr_H_Byte; |
charliex | 4:53ef91c87d74 | 108 | BYTE PPU_Scr_H_Byte_Next; |
charliex | 4:53ef91c87d74 | 109 | BYTE PPU_Scr_H_Bit; |
charliex | 4:53ef91c87d74 | 110 | BYTE PPU_Scr_H_Bit_Next; |
charliex | 4:53ef91c87d74 | 111 | |
charliex | 4:53ef91c87d74 | 112 | /* PPU Address */ |
charliex | 4:53ef91c87d74 | 113 | WORD PPU_Addr; |
charliex | 4:53ef91c87d74 | 114 | |
charliex | 4:53ef91c87d74 | 115 | /* The increase value of the PPU Address */ |
charliex | 4:53ef91c87d74 | 116 | WORD PPU_Increment; |
charliex | 4:53ef91c87d74 | 117 | |
charliex | 4:53ef91c87d74 | 118 | /* Current Scanline */ |
charliex | 4:53ef91c87d74 | 119 | WORD PPU_Scanline; |
charliex | 4:53ef91c87d74 | 120 | |
charliex | 4:53ef91c87d74 | 121 | /* Scanline Table */ |
charliex | 4:53ef91c87d74 | 122 | //BYTE PPU_ScanTable[ 263 ]; |
charliex | 4:53ef91c87d74 | 123 | |
charliex | 4:53ef91c87d74 | 124 | /* Name Table Bank */ |
charliex | 4:53ef91c87d74 | 125 | BYTE PPU_NameTableBank; |
charliex | 4:53ef91c87d74 | 126 | |
charliex | 4:53ef91c87d74 | 127 | /* BG Base Address */ |
charliex | 4:53ef91c87d74 | 128 | BYTE *PPU_BG_Base; |
charliex | 4:53ef91c87d74 | 129 | |
charliex | 4:53ef91c87d74 | 130 | /* Sprite Base Address */ |
charliex | 4:53ef91c87d74 | 131 | BYTE *PPU_SP_Base; |
charliex | 4:53ef91c87d74 | 132 | |
charliex | 4:53ef91c87d74 | 133 | /* Sprite Height */ |
charliex | 4:53ef91c87d74 | 134 | WORD PPU_SP_Height; |
charliex | 4:53ef91c87d74 | 135 | |
charliex | 4:53ef91c87d74 | 136 | /* Sprite #0 Scanline Hit Position */ |
charliex | 4:53ef91c87d74 | 137 | int SpriteHitPos; |
charliex | 4:53ef91c87d74 | 138 | |
charliex | 4:53ef91c87d74 | 139 | /*-------------------------------------------------------------------*/ |
charliex | 4:53ef91c87d74 | 140 | /* Display and Others resouces */ |
charliex | 4:53ef91c87d74 | 141 | /*-------------------------------------------------------------------*/ |
charliex | 4:53ef91c87d74 | 142 | |
charliex | 4:53ef91c87d74 | 143 | /* Frame Skip */ |
charliex | 4:53ef91c87d74 | 144 | WORD FrameSkip; |
charliex | 4:53ef91c87d74 | 145 | WORD FrameCnt; |
charliex | 4:53ef91c87d74 | 146 | bool FrameDraw; |
charliex | 4:53ef91c87d74 | 147 | |
charliex | 4:53ef91c87d74 | 148 | /* Display Line Buffer */ |
charliex | 4:53ef91c87d74 | 149 | WORD LineData[2][ NES_DISP_WIDTH ]; |
charliex | 4:53ef91c87d74 | 150 | WORD *pDrawData; |
charliex | 4:53ef91c87d74 | 151 | int LineDataIdx; |
charliex | 4:53ef91c87d74 | 152 | |
charliex | 4:53ef91c87d74 | 153 | /* Character Buffer */ |
charliex | 4:53ef91c87d74 | 154 | BYTE ChrBuf[ 256 * 2 * 8 * 8 ]; |
charliex | 4:53ef91c87d74 | 155 | |
charliex | 4:53ef91c87d74 | 156 | /* Update flag for ChrBuf */ |
charliex | 4:53ef91c87d74 | 157 | BYTE ChrBufUpdate; |
charliex | 4:53ef91c87d74 | 158 | |
charliex | 4:53ef91c87d74 | 159 | /* Palette Table */ |
charliex | 4:53ef91c87d74 | 160 | WORD PalTable[ 32 ]; |
charliex | 4:53ef91c87d74 | 161 | |
charliex | 4:53ef91c87d74 | 162 | /* Table for Mirroring */ |
charliex | 4:53ef91c87d74 | 163 | const BYTE PPU_MirrorTable[][ 4 ] = |
charliex | 4:53ef91c87d74 | 164 | { |
charliex | 4:53ef91c87d74 | 165 | { NAME_TABLE0, NAME_TABLE0, NAME_TABLE1, NAME_TABLE1 }, |
charliex | 4:53ef91c87d74 | 166 | { NAME_TABLE0, NAME_TABLE1, NAME_TABLE0, NAME_TABLE1 }, |
charliex | 4:53ef91c87d74 | 167 | { NAME_TABLE1, NAME_TABLE1, NAME_TABLE1, NAME_TABLE1 }, |
charliex | 4:53ef91c87d74 | 168 | { NAME_TABLE0, NAME_TABLE0, NAME_TABLE0, NAME_TABLE0 } |
charliex | 4:53ef91c87d74 | 169 | }; |
charliex | 4:53ef91c87d74 | 170 | |
charliex | 4:53ef91c87d74 | 171 | /*-------------------------------------------------------------------*/ |
charliex | 4:53ef91c87d74 | 172 | /* APU and Pad resources */ |
charliex | 4:53ef91c87d74 | 173 | /*-------------------------------------------------------------------*/ |
charliex | 4:53ef91c87d74 | 174 | |
charliex | 4:53ef91c87d74 | 175 | /* APU Register */ |
charliex | 4:53ef91c87d74 | 176 | BYTE APU_Reg[ 0x18 ]; |
charliex | 4:53ef91c87d74 | 177 | |
charliex | 4:53ef91c87d74 | 178 | /* Pad data */ |
charliex | 4:53ef91c87d74 | 179 | DWORD PAD1_Latch; |
charliex | 4:53ef91c87d74 | 180 | DWORD PAD2_Latch; |
charliex | 4:53ef91c87d74 | 181 | DWORD PAD_System; |
charliex | 4:53ef91c87d74 | 182 | DWORD PAD1_Bit; |
charliex | 4:53ef91c87d74 | 183 | DWORD PAD2_Bit; |
charliex | 4:53ef91c87d74 | 184 | |
charliex | 4:53ef91c87d74 | 185 | /*-------------------------------------------------------------------*/ |
charliex | 4:53ef91c87d74 | 186 | /* Mapper Function */ |
charliex | 4:53ef91c87d74 | 187 | /*-------------------------------------------------------------------*/ |
charliex | 4:53ef91c87d74 | 188 | |
charliex | 4:53ef91c87d74 | 189 | /* Initialize Mapper */ |
charliex | 4:53ef91c87d74 | 190 | void (*MapperInit)(); |
charliex | 4:53ef91c87d74 | 191 | /* Write to Mapper */ |
charliex | 4:53ef91c87d74 | 192 | void (*MapperWrite)( WORD wAddr, BYTE byData ); |
charliex | 4:53ef91c87d74 | 193 | /* Callback at VSync */ |
charliex | 4:53ef91c87d74 | 194 | void (*MapperVSync)(); |
charliex | 4:53ef91c87d74 | 195 | /* Callback at HSync */ |
charliex | 4:53ef91c87d74 | 196 | void (*MapperHSync)(); |
charliex | 4:53ef91c87d74 | 197 | |
charliex | 4:53ef91c87d74 | 198 | /*-------------------------------------------------------------------*/ |
charliex | 4:53ef91c87d74 | 199 | /* ROM information */ |
charliex | 4:53ef91c87d74 | 200 | /*-------------------------------------------------------------------*/ |
charliex | 4:53ef91c87d74 | 201 | |
charliex | 4:53ef91c87d74 | 202 | /* .nes File Header */ |
charliex | 4:53ef91c87d74 | 203 | struct NesHeader_tag NesHeader; |
charliex | 4:53ef91c87d74 | 204 | |
charliex | 4:53ef91c87d74 | 205 | /* Mapper Number */ |
charliex | 4:53ef91c87d74 | 206 | BYTE MapperNo; |
charliex | 4:53ef91c87d74 | 207 | |
charliex | 4:53ef91c87d74 | 208 | /* Mirroring 0:Horizontal 1:Vertical */ |
charliex | 4:53ef91c87d74 | 209 | BYTE ROM_Mirroring; |
charliex | 4:53ef91c87d74 | 210 | /* It has SRAM */ |
charliex | 4:53ef91c87d74 | 211 | BYTE ROM_SRAM; |
charliex | 4:53ef91c87d74 | 212 | /* It has Trainer */ |
charliex | 4:53ef91c87d74 | 213 | BYTE ROM_Trainer; |
charliex | 4:53ef91c87d74 | 214 | /* Four screen VRAM */ |
charliex | 4:53ef91c87d74 | 215 | BYTE ROM_FourScr; |
charliex | 4:53ef91c87d74 | 216 | |
charliex | 4:53ef91c87d74 | 217 | /*===================================================================*/ |
charliex | 4:53ef91c87d74 | 218 | /* */ |
charliex | 4:53ef91c87d74 | 219 | /* pNesX_Init() : Initialize pNesX */ |
charliex | 4:53ef91c87d74 | 220 | /* */ |
charliex | 4:53ef91c87d74 | 221 | /*===================================================================*/ |
charliex | 4:53ef91c87d74 | 222 | void pNesX_Init() |
charliex | 4:53ef91c87d74 | 223 | { |
charliex | 4:53ef91c87d74 | 224 | /* |
charliex | 4:53ef91c87d74 | 225 | * Initialize pNesX |
charliex | 4:53ef91c87d74 | 226 | * |
charliex | 4:53ef91c87d74 | 227 | * Remarks |
charliex | 4:53ef91c87d74 | 228 | * Initialize K6502 and Scanline Table. |
charliex | 4:53ef91c87d74 | 229 | */ |
charliex | 4:53ef91c87d74 | 230 | |
charliex | 4:53ef91c87d74 | 231 | // Initialize 6502 |
charliex | 4:53ef91c87d74 | 232 | K6502_Init(); |
charliex | 4:53ef91c87d74 | 233 | } |
charliex | 4:53ef91c87d74 | 234 | |
charliex | 4:53ef91c87d74 | 235 | /*===================================================================*/ |
charliex | 4:53ef91c87d74 | 236 | /* */ |
charliex | 4:53ef91c87d74 | 237 | /* pNesX_Fin() : Completion treatment */ |
charliex | 4:53ef91c87d74 | 238 | /* */ |
charliex | 4:53ef91c87d74 | 239 | /*===================================================================*/ |
charliex | 4:53ef91c87d74 | 240 | void pNesX_Fin() |
charliex | 4:53ef91c87d74 | 241 | { |
charliex | 4:53ef91c87d74 | 242 | /* |
charliex | 4:53ef91c87d74 | 243 | * Completion treatment |
charliex | 4:53ef91c87d74 | 244 | * |
charliex | 4:53ef91c87d74 | 245 | * Remarks |
charliex | 4:53ef91c87d74 | 246 | * Release resources |
charliex | 4:53ef91c87d74 | 247 | */ |
charliex | 4:53ef91c87d74 | 248 | |
charliex | 4:53ef91c87d74 | 249 | // Release a memory for ROM |
charliex | 4:53ef91c87d74 | 250 | pNesX_ReleaseRom(); |
charliex | 4:53ef91c87d74 | 251 | } |
charliex | 4:53ef91c87d74 | 252 | |
charliex | 4:53ef91c87d74 | 253 | /*===================================================================*/ |
charliex | 4:53ef91c87d74 | 254 | /* */ |
charliex | 4:53ef91c87d74 | 255 | /* pNesX_Load() : Load a cassette */ |
charliex | 4:53ef91c87d74 | 256 | /* */ |
charliex | 4:53ef91c87d74 | 257 | /*===================================================================*/ |
charliex | 4:53ef91c87d74 | 258 | int pNesX_Load( const char *pszFileName ) |
charliex | 4:53ef91c87d74 | 259 | { |
charliex | 4:53ef91c87d74 | 260 | /* |
charliex | 4:53ef91c87d74 | 261 | * Load a cassette |
charliex | 4:53ef91c87d74 | 262 | * |
charliex | 4:53ef91c87d74 | 263 | * Parameters |
charliex | 4:53ef91c87d74 | 264 | * const char *pszFileName (Read) |
charliex | 4:53ef91c87d74 | 265 | * File name of ROM image |
charliex | 4:53ef91c87d74 | 266 | * |
charliex | 4:53ef91c87d74 | 267 | * Return values |
charliex | 4:53ef91c87d74 | 268 | * 0 : It was finished normally. |
charliex | 4:53ef91c87d74 | 269 | * -1 : An error occurred. |
charliex | 4:53ef91c87d74 | 270 | * |
charliex | 4:53ef91c87d74 | 271 | * Remarks |
charliex | 4:53ef91c87d74 | 272 | * Read a ROM image in the memory. |
charliex | 4:53ef91c87d74 | 273 | * Reset pNesX. |
charliex | 4:53ef91c87d74 | 274 | */ |
charliex | 4:53ef91c87d74 | 275 | |
charliex | 4:53ef91c87d74 | 276 | // Release a memory for ROM |
charliex | 4:53ef91c87d74 | 277 | pNesX_ReleaseRom(); |
charliex | 4:53ef91c87d74 | 278 | |
charliex | 4:53ef91c87d74 | 279 | // Read a ROM image in the memory |
charliex | 4:53ef91c87d74 | 280 | if ( pNesX_ReadRom( pszFileName ) < 0 ) |
charliex | 4:53ef91c87d74 | 281 | return -1; |
charliex | 4:53ef91c87d74 | 282 | |
charliex | 4:53ef91c87d74 | 283 | // Reset pNesX |
charliex | 4:53ef91c87d74 | 284 | if ( pNesX_Reset() < 0 ) |
charliex | 4:53ef91c87d74 | 285 | return -1; |
charliex | 4:53ef91c87d74 | 286 | |
charliex | 4:53ef91c87d74 | 287 | // Successful |
charliex | 4:53ef91c87d74 | 288 | return 0; |
charliex | 4:53ef91c87d74 | 289 | } |
charliex | 4:53ef91c87d74 | 290 | |
charliex | 4:53ef91c87d74 | 291 | /*===================================================================*/ |
charliex | 4:53ef91c87d74 | 292 | /* */ |
charliex | 4:53ef91c87d74 | 293 | /* pNesX_Reset() : Reset pNesX */ |
charliex | 4:53ef91c87d74 | 294 | /* */ |
charliex | 4:53ef91c87d74 | 295 | /*===================================================================*/ |
charliex | 4:53ef91c87d74 | 296 | int pNesX_Reset() |
charliex | 4:53ef91c87d74 | 297 | { |
charliex | 4:53ef91c87d74 | 298 | /* |
charliex | 4:53ef91c87d74 | 299 | * Reset pNesX |
charliex | 4:53ef91c87d74 | 300 | * |
charliex | 4:53ef91c87d74 | 301 | * Return values |
charliex | 4:53ef91c87d74 | 302 | * 0 : Normally |
charliex | 4:53ef91c87d74 | 303 | * -1 : Non support mapper |
charliex | 4:53ef91c87d74 | 304 | * |
charliex | 4:53ef91c87d74 | 305 | * Remarks |
charliex | 4:53ef91c87d74 | 306 | * Initialize Resources, PPU and Mapper. |
charliex | 4:53ef91c87d74 | 307 | * Reset CPU. |
charliex | 4:53ef91c87d74 | 308 | */ |
charliex | 4:53ef91c87d74 | 309 | |
charliex | 4:53ef91c87d74 | 310 | int nIdx; |
charliex | 4:53ef91c87d74 | 311 | |
charliex | 4:53ef91c87d74 | 312 | /*-------------------------------------------------------------------*/ |
charliex | 4:53ef91c87d74 | 313 | /* Get information on the cassette */ |
charliex | 4:53ef91c87d74 | 314 | /*-------------------------------------------------------------------*/ |
charliex | 4:53ef91c87d74 | 315 | |
charliex | 4:53ef91c87d74 | 316 | // Get Mapper Number |
charliex | 4:53ef91c87d74 | 317 | MapperNo = NesHeader.byInfo1 >> 4; |
charliex | 4:53ef91c87d74 | 318 | |
charliex | 4:53ef91c87d74 | 319 | // Check bit counts of Mapper No. |
charliex | 4:53ef91c87d74 | 320 | for ( nIdx = 4; nIdx < 8 && NesHeader.byReserve[ nIdx ] == 0; ++nIdx ) |
charliex | 4:53ef91c87d74 | 321 | ; |
charliex | 4:53ef91c87d74 | 322 | |
charliex | 4:53ef91c87d74 | 323 | if ( nIdx == 8 ) |
charliex | 4:53ef91c87d74 | 324 | { |
charliex | 4:53ef91c87d74 | 325 | // Mapper Number is 8bits |
charliex | 4:53ef91c87d74 | 326 | MapperNo |= ( NesHeader.byInfo2 & 0xf0 ); |
charliex | 4:53ef91c87d74 | 327 | } |
charliex | 4:53ef91c87d74 | 328 | |
charliex | 4:53ef91c87d74 | 329 | // Get information on the ROM |
charliex | 4:53ef91c87d74 | 330 | ROM_Mirroring = NesHeader.byInfo1 & 1; |
charliex | 4:53ef91c87d74 | 331 | ROM_SRAM = NesHeader.byInfo1 & 2; |
charliex | 4:53ef91c87d74 | 332 | ROM_Trainer = NesHeader.byInfo1 & 4; |
charliex | 4:53ef91c87d74 | 333 | ROM_FourScr = NesHeader.byInfo1 & 8; |
charliex | 4:53ef91c87d74 | 334 | |
charliex | 4:53ef91c87d74 | 335 | /*-------------------------------------------------------------------*/ |
charliex | 4:53ef91c87d74 | 336 | /* Initialize resources */ |
charliex | 4:53ef91c87d74 | 337 | /*-------------------------------------------------------------------*/ |
charliex | 4:53ef91c87d74 | 338 | |
charliex | 4:53ef91c87d74 | 339 | // Clear RAM |
charliex | 4:53ef91c87d74 | 340 | pNesX_MemorySet( RAM, 0, sizeof RAM ); |
charliex | 4:53ef91c87d74 | 341 | |
charliex | 4:53ef91c87d74 | 342 | // Reset frame skip and frame count |
charliex | 4:53ef91c87d74 | 343 | FrameSkip = 2; // 0:full 1:half 2:2/3 3:1/3 |
charliex | 4:53ef91c87d74 | 344 | FrameCnt = 0; |
charliex | 4:53ef91c87d74 | 345 | |
charliex | 4:53ef91c87d74 | 346 | |
charliex | 4:53ef91c87d74 | 347 | // Reset update flag of ChrBuf |
charliex | 4:53ef91c87d74 | 348 | ChrBufUpdate = 0xff; |
charliex | 4:53ef91c87d74 | 349 | |
charliex | 4:53ef91c87d74 | 350 | // Reset palette table |
charliex | 4:53ef91c87d74 | 351 | pNesX_MemorySet( PalTable, 0, sizeof PalTable ); |
charliex | 4:53ef91c87d74 | 352 | |
charliex | 4:53ef91c87d74 | 353 | // Reset APU register |
charliex | 4:53ef91c87d74 | 354 | pNesX_MemorySet( APU_Reg, 0, sizeof APU_Reg ); |
charliex | 4:53ef91c87d74 | 355 | |
charliex | 4:53ef91c87d74 | 356 | // Reset joypad |
charliex | 4:53ef91c87d74 | 357 | PAD1_Latch = PAD2_Latch = PAD_System = 0; |
charliex | 4:53ef91c87d74 | 358 | PAD1_Bit = PAD2_Bit = 0; |
charliex | 4:53ef91c87d74 | 359 | |
charliex | 4:53ef91c87d74 | 360 | /*-------------------------------------------------------------------*/ |
charliex | 4:53ef91c87d74 | 361 | /* Initialize PPU */ |
charliex | 4:53ef91c87d74 | 362 | /*-------------------------------------------------------------------*/ |
charliex | 4:53ef91c87d74 | 363 | |
charliex | 4:53ef91c87d74 | 364 | pNesX_SetupPPU(); |
charliex | 4:53ef91c87d74 | 365 | |
charliex | 4:53ef91c87d74 | 366 | /*-------------------------------------------------------------------*/ |
charliex | 4:53ef91c87d74 | 367 | /* Initialize Mapper */ |
charliex | 4:53ef91c87d74 | 368 | /*-------------------------------------------------------------------*/ |
charliex | 4:53ef91c87d74 | 369 | |
charliex | 4:53ef91c87d74 | 370 | // Get Mapper Table Index |
charliex | 4:53ef91c87d74 | 371 | for ( nIdx = 0; MapperTable[ nIdx ].nMapperNo != -1; ++nIdx ) |
charliex | 4:53ef91c87d74 | 372 | { |
charliex | 4:53ef91c87d74 | 373 | if ( MapperTable[ nIdx ].nMapperNo == MapperNo ) |
charliex | 4:53ef91c87d74 | 374 | break; |
charliex | 4:53ef91c87d74 | 375 | } |
charliex | 4:53ef91c87d74 | 376 | |
charliex | 4:53ef91c87d74 | 377 | if ( MapperTable[ nIdx ].nMapperNo == -1 ) |
charliex | 4:53ef91c87d74 | 378 | { |
charliex | 4:53ef91c87d74 | 379 | // Non support mapper |
charliex | 4:53ef91c87d74 | 380 | return -1; |
charliex | 4:53ef91c87d74 | 381 | } |
charliex | 4:53ef91c87d74 | 382 | |
charliex | 4:53ef91c87d74 | 383 | // Set up a mapper initialization function |
charliex | 4:53ef91c87d74 | 384 | MapperTable[ nIdx ].pMapperInit(); |
charliex | 4:53ef91c87d74 | 385 | |
charliex | 4:53ef91c87d74 | 386 | /*-------------------------------------------------------------------*/ |
charliex | 4:53ef91c87d74 | 387 | /* Reset CPU */ |
charliex | 4:53ef91c87d74 | 388 | /*-------------------------------------------------------------------*/ |
charliex | 4:53ef91c87d74 | 389 | |
charliex | 4:53ef91c87d74 | 390 | K6502_Reset(); |
charliex | 4:53ef91c87d74 | 391 | |
charliex | 4:53ef91c87d74 | 392 | // Successful |
charliex | 4:53ef91c87d74 | 393 | return 0; |
charliex | 4:53ef91c87d74 | 394 | } |
charliex | 4:53ef91c87d74 | 395 | |
charliex | 4:53ef91c87d74 | 396 | /*===================================================================*/ |
charliex | 4:53ef91c87d74 | 397 | /* */ |
charliex | 4:53ef91c87d74 | 398 | /* pNesX_SetupPPU() : Initialize PPU */ |
charliex | 4:53ef91c87d74 | 399 | /* */ |
charliex | 4:53ef91c87d74 | 400 | /*===================================================================*/ |
charliex | 4:53ef91c87d74 | 401 | void pNesX_SetupPPU() |
charliex | 4:53ef91c87d74 | 402 | { |
charliex | 4:53ef91c87d74 | 403 | /* |
charliex | 4:53ef91c87d74 | 404 | * Initialize PPU |
charliex | 4:53ef91c87d74 | 405 | * |
charliex | 4:53ef91c87d74 | 406 | */ |
charliex | 4:53ef91c87d74 | 407 | int nPage; |
charliex | 4:53ef91c87d74 | 408 | |
charliex | 4:53ef91c87d74 | 409 | // Clear PPU and Sprite Memory |
charliex | 4:53ef91c87d74 | 410 | pNesX_MemorySet( PPURAM, 0, sizeof PPURAM ); |
charliex | 4:53ef91c87d74 | 411 | pNesX_MemorySet( SPRRAM, 0, sizeof SPRRAM ); |
charliex | 4:53ef91c87d74 | 412 | |
charliex | 4:53ef91c87d74 | 413 | // Reset PPU Register |
charliex | 4:53ef91c87d74 | 414 | PPU_R0 = PPU_R1 = PPU_R2 = PPU_R3 = PPU_R7 = 0; |
charliex | 4:53ef91c87d74 | 415 | |
charliex | 4:53ef91c87d74 | 416 | // Reset latch flag |
charliex | 4:53ef91c87d74 | 417 | PPU_Latch_Flag = 0; |
charliex | 4:53ef91c87d74 | 418 | |
charliex | 4:53ef91c87d74 | 419 | // Reset Scroll values |
charliex | 4:53ef91c87d74 | 420 | PPU_Scr_V = PPU_Scr_V_Next = PPU_Scr_V_Byte = PPU_Scr_V_Byte_Next = PPU_Scr_V_Bit = PPU_Scr_V_Bit_Next = 0; |
charliex | 4:53ef91c87d74 | 421 | PPU_Scr_H = PPU_Scr_H_Next = PPU_Scr_H_Byte = PPU_Scr_H_Byte_Next = PPU_Scr_H_Bit = PPU_Scr_H_Bit_Next = 0; |
charliex | 4:53ef91c87d74 | 422 | |
charliex | 4:53ef91c87d74 | 423 | // Reset PPU address |
charliex | 4:53ef91c87d74 | 424 | PPU_Addr = 0; |
charliex | 4:53ef91c87d74 | 425 | |
charliex | 4:53ef91c87d74 | 426 | // Reset scanline |
charliex | 4:53ef91c87d74 | 427 | PPU_Scanline = 0; |
charliex | 4:53ef91c87d74 | 428 | |
charliex | 4:53ef91c87d74 | 429 | // Reset hit position of sprite #0 |
charliex | 4:53ef91c87d74 | 430 | SpriteHitPos = 0; |
charliex | 4:53ef91c87d74 | 431 | |
charliex | 4:53ef91c87d74 | 432 | // Reset information on PPU_R0 |
charliex | 4:53ef91c87d74 | 433 | PPU_Increment = 1; |
charliex | 4:53ef91c87d74 | 434 | PPU_NameTableBank = NAME_TABLE0; |
charliex | 4:53ef91c87d74 | 435 | PPU_BG_Base = ChrBuf; |
charliex | 4:53ef91c87d74 | 436 | PPU_SP_Base = ChrBuf + 256 * 64; |
charliex | 4:53ef91c87d74 | 437 | PPU_SP_Height = 8; |
charliex | 4:53ef91c87d74 | 438 | |
charliex | 4:53ef91c87d74 | 439 | // Reset PPU banks |
charliex | 4:53ef91c87d74 | 440 | for ( nPage = 0; nPage < 16; ++nPage ) |
charliex | 4:53ef91c87d74 | 441 | PPUBANK[ nPage ] = &PPURAM[ nPage * 0x400 ]; |
charliex | 4:53ef91c87d74 | 442 | |
charliex | 4:53ef91c87d74 | 443 | /* Mirroring of Name Table */ |
charliex | 4:53ef91c87d74 | 444 | pNesX_Mirroring( ROM_Mirroring ); |
charliex | 4:53ef91c87d74 | 445 | } |
charliex | 4:53ef91c87d74 | 446 | |
charliex | 4:53ef91c87d74 | 447 | /*===================================================================*/ |
charliex | 4:53ef91c87d74 | 448 | /* */ |
charliex | 4:53ef91c87d74 | 449 | /* pNesX_Mirroring() : Set up a Mirroring of Name Table */ |
charliex | 4:53ef91c87d74 | 450 | /* */ |
charliex | 4:53ef91c87d74 | 451 | /*===================================================================*/ |
charliex | 4:53ef91c87d74 | 452 | void pNesX_Mirroring( int nType ) |
charliex | 4:53ef91c87d74 | 453 | { |
charliex | 4:53ef91c87d74 | 454 | /* |
charliex | 4:53ef91c87d74 | 455 | * Set up a Mirroring of Name Table |
charliex | 4:53ef91c87d74 | 456 | * |
charliex | 4:53ef91c87d74 | 457 | * Parameters |
charliex | 4:53ef91c87d74 | 458 | * int nType (Read) |
charliex | 4:53ef91c87d74 | 459 | * Mirroring Type |
charliex | 4:53ef91c87d74 | 460 | * 0 : Horizontal |
charliex | 4:53ef91c87d74 | 461 | * 1 : Vertical |
charliex | 4:53ef91c87d74 | 462 | * 2 : One Screen 0x2000 |
charliex | 4:53ef91c87d74 | 463 | * 3 : One Screen 0x2400 |
charliex | 4:53ef91c87d74 | 464 | */ |
charliex | 4:53ef91c87d74 | 465 | |
charliex | 4:53ef91c87d74 | 466 | PPUBANK[ NAME_TABLE0 ] = &PPURAM[ PPU_MirrorTable[ nType ][ 0 ] * 0x400 ]; |
charliex | 4:53ef91c87d74 | 467 | PPUBANK[ NAME_TABLE1 ] = &PPURAM[ PPU_MirrorTable[ nType ][ 1 ] * 0x400 ]; |
charliex | 4:53ef91c87d74 | 468 | PPUBANK[ NAME_TABLE2 ] = &PPURAM[ PPU_MirrorTable[ nType ][ 2 ] * 0x400 ]; |
charliex | 4:53ef91c87d74 | 469 | PPUBANK[ NAME_TABLE3 ] = &PPURAM[ PPU_MirrorTable[ nType ][ 3 ] * 0x400 ]; |
charliex | 4:53ef91c87d74 | 470 | } |
charliex | 4:53ef91c87d74 | 471 | extern DigitalOut back; |
charliex | 4:53ef91c87d74 | 472 | |
charliex | 4:53ef91c87d74 | 473 | int backlight(float); |
charliex | 4:53ef91c87d74 | 474 | /*===================================================================*/ |
charliex | 4:53ef91c87d74 | 475 | /* */ |
charliex | 4:53ef91c87d74 | 476 | /* pNesX_Main() : The main loop of pNesX */ |
charliex | 4:53ef91c87d74 | 477 | /* */ |
charliex | 4:53ef91c87d74 | 478 | /*===================================================================*/ |
charliex | 4:53ef91c87d74 | 479 | void pNesX_Main() |
charliex | 4:53ef91c87d74 | 480 | { |
charliex | 4:53ef91c87d74 | 481 | |
charliex | 4:53ef91c87d74 | 482 | /* |
charliex | 4:53ef91c87d74 | 483 | * The main loop of pNesX |
charliex | 4:53ef91c87d74 | 484 | * |
charliex | 4:53ef91c87d74 | 485 | */ |
charliex | 4:53ef91c87d74 | 486 | |
charliex | 4:53ef91c87d74 | 487 | // Initialize pNesX |
charliex | 4:53ef91c87d74 | 488 | pNesX_Init(); |
charliex | 4:53ef91c87d74 | 489 | |
charliex | 4:53ef91c87d74 | 490 | backlight(.8 ); |
charliex | 4:53ef91c87d74 | 491 | |
charliex | 4:53ef91c87d74 | 492 | // Main loop |
charliex | 4:53ef91c87d74 | 493 | while ( 1 ) |
charliex | 4:53ef91c87d74 | 494 | { |
charliex | 4:53ef91c87d74 | 495 | |
charliex | 4:53ef91c87d74 | 496 | back = !back; |
charliex | 4:53ef91c87d74 | 497 | |
charliex | 4:53ef91c87d74 | 498 | /*-------------------------------------------------------------------*/ |
charliex | 4:53ef91c87d74 | 499 | /* To the menu screen */ |
charliex | 4:53ef91c87d74 | 500 | /*-------------------------------------------------------------------*/ |
charliex | 4:53ef91c87d74 | 501 | if ( pNesX_Menu() == -1 ) |
charliex | 4:53ef91c87d74 | 502 | { |
charliex | 4:53ef91c87d74 | 503 | break; // Quit |
charliex | 4:53ef91c87d74 | 504 | } |
charliex | 4:53ef91c87d74 | 505 | |
charliex | 4:53ef91c87d74 | 506 | /*-------------------------------------------------------------------*/ |
charliex | 4:53ef91c87d74 | 507 | /* Start a NES emulation */ |
charliex | 4:53ef91c87d74 | 508 | /*-------------------------------------------------------------------*/ |
charliex | 4:53ef91c87d74 | 509 | pNesX_Cycle(); |
charliex | 4:53ef91c87d74 | 510 | |
charliex | 4:53ef91c87d74 | 511 | |
charliex | 4:53ef91c87d74 | 512 | } |
charliex | 4:53ef91c87d74 | 513 | |
charliex | 4:53ef91c87d74 | 514 | // Completion treatment |
charliex | 4:53ef91c87d74 | 515 | pNesX_Fin(); |
charliex | 4:53ef91c87d74 | 516 | } |
charliex | 4:53ef91c87d74 | 517 | |
charliex | 4:53ef91c87d74 | 518 | /*===================================================================*/ |
charliex | 4:53ef91c87d74 | 519 | /* */ |
charliex | 4:53ef91c87d74 | 520 | /* pNesX_Cycle() : The loop of emulation */ |
charliex | 4:53ef91c87d74 | 521 | /* */ |
charliex | 4:53ef91c87d74 | 522 | /*===================================================================*/ |
charliex | 4:53ef91c87d74 | 523 | void pNesX_Cycle() |
charliex | 4:53ef91c87d74 | 524 | { |
charliex | 4:53ef91c87d74 | 525 | /* |
charliex | 4:53ef91c87d74 | 526 | * The loop of emulation |
charliex | 4:53ef91c87d74 | 527 | * |
charliex | 4:53ef91c87d74 | 528 | */ |
charliex | 4:53ef91c87d74 | 529 | |
charliex | 4:53ef91c87d74 | 530 | // Emulation loop |
charliex | 4:53ef91c87d74 | 531 | for (;;) |
charliex | 4:53ef91c87d74 | 532 | { |
charliex | 4:53ef91c87d74 | 533 | bLED2 = !bLED1; |
charliex | 4:53ef91c87d74 | 534 | |
charliex | 4:53ef91c87d74 | 535 | // Execute instructions |
charliex | 4:53ef91c87d74 | 536 | K6502_Step( 40 ); |
charliex | 4:53ef91c87d74 | 537 | |
charliex | 4:53ef91c87d74 | 538 | // Set a flag if a scanning line is a hit in the sprite #0 |
charliex | 4:53ef91c87d74 | 539 | if ( ( SPRRAM[ SPR_Y ] + SpriteHitPos ) == PPU_Scanline && |
charliex | 4:53ef91c87d74 | 540 | PPU_Scanline >= SCAN_ON_SCREEN_START && PPU_Scanline < SCAN_BOTTOM_OFF_SCREEN_START ) |
charliex | 4:53ef91c87d74 | 541 | //PPU_ScanTable[ PPU_Scanline ] == SCAN_ON_SCREEN ) |
charliex | 4:53ef91c87d74 | 542 | { |
charliex | 4:53ef91c87d74 | 543 | // Set a sprite hit flag |
charliex | 4:53ef91c87d74 | 544 | PPU_R2 |= R2_HIT_SP; |
charliex | 4:53ef91c87d74 | 545 | |
charliex | 4:53ef91c87d74 | 546 | // NMI is required if there is necessity |
charliex | 4:53ef91c87d74 | 547 | if ( ( PPU_R0 & R0_NMI_SP ) && ( PPU_R1 & R1_SHOW_SP ) ) |
charliex | 4:53ef91c87d74 | 548 | NMI_REQ; |
charliex | 4:53ef91c87d74 | 549 | } |
charliex | 4:53ef91c87d74 | 550 | |
charliex | 4:53ef91c87d74 | 551 | // Execute instructions |
charliex | 4:53ef91c87d74 | 552 | K6502_Step( 75 ); |
charliex | 4:53ef91c87d74 | 553 | |
charliex | 4:53ef91c87d74 | 554 | // A mapper function in H-Sync |
charliex | 4:53ef91c87d74 | 555 | MapperHSync(); |
charliex | 4:53ef91c87d74 | 556 | |
charliex | 4:53ef91c87d74 | 557 | // A function in H-Sync |
charliex | 4:53ef91c87d74 | 558 | if ( pNesX_HSync() == -1 ) |
charliex | 4:53ef91c87d74 | 559 | return; // To the menu screen |
charliex | 4:53ef91c87d74 | 560 | } |
charliex | 4:53ef91c87d74 | 561 | } |
charliex | 4:53ef91c87d74 | 562 | |
charliex | 4:53ef91c87d74 | 563 | /*===================================================================*/ |
charliex | 4:53ef91c87d74 | 564 | /* */ |
charliex | 4:53ef91c87d74 | 565 | /* pNesX_HSync() : A function in H-Sync */ |
charliex | 4:53ef91c87d74 | 566 | /* */ |
charliex | 4:53ef91c87d74 | 567 | /*===================================================================*/ |
charliex | 4:53ef91c87d74 | 568 | int pNesX_HSync() |
charliex | 4:53ef91c87d74 | 569 | |
charliex | 4:53ef91c87d74 | 570 | { |
charliex | 4:53ef91c87d74 | 571 | /* |
charliex | 4:53ef91c87d74 | 572 | * A function in H-Sync |
charliex | 4:53ef91c87d74 | 573 | * |
charliex | 4:53ef91c87d74 | 574 | * Return values |
charliex | 4:53ef91c87d74 | 575 | * 0 : Normally |
charliex | 4:53ef91c87d74 | 576 | * -1 : Exit an emulation |
charliex | 4:53ef91c87d74 | 577 | */ |
charliex | 4:53ef91c87d74 | 578 | |
charliex | 4:53ef91c87d74 | 579 | /*-------------------------------------------------------------------*/ |
charliex | 4:53ef91c87d74 | 580 | /* Render a scanline */ |
charliex | 4:53ef91c87d74 | 581 | /*-------------------------------------------------------------------*/ |
charliex | 4:53ef91c87d74 | 582 | if ( FrameDraw && |
charliex | 4:53ef91c87d74 | 583 | PPU_Scanline >= SCAN_ON_SCREEN_START && PPU_Scanline < SCAN_BOTTOM_OFF_SCREEN_START ) |
charliex | 4:53ef91c87d74 | 584 | { |
charliex | 4:53ef91c87d74 | 585 | pNesX_DrawLine(); |
charliex | 4:53ef91c87d74 | 586 | pNesX_TransmitLinedata(); |
charliex | 4:53ef91c87d74 | 587 | } |
charliex | 4:53ef91c87d74 | 588 | |
charliex | 4:53ef91c87d74 | 589 | /*-------------------------------------------------------------------*/ |
charliex | 4:53ef91c87d74 | 590 | /* Set new scroll values */ |
charliex | 4:53ef91c87d74 | 591 | /*-------------------------------------------------------------------*/ |
charliex | 4:53ef91c87d74 | 592 | PPU_Scr_V = PPU_Scr_V_Next; |
charliex | 4:53ef91c87d74 | 593 | PPU_Scr_V_Byte = PPU_Scr_V_Byte_Next; |
charliex | 4:53ef91c87d74 | 594 | PPU_Scr_V_Bit = PPU_Scr_V_Bit_Next; |
charliex | 4:53ef91c87d74 | 595 | |
charliex | 4:53ef91c87d74 | 596 | PPU_Scr_H = PPU_Scr_H_Next; |
charliex | 4:53ef91c87d74 | 597 | PPU_Scr_H_Byte = PPU_Scr_H_Byte_Next; |
charliex | 4:53ef91c87d74 | 598 | PPU_Scr_H_Bit = PPU_Scr_H_Bit_Next; |
charliex | 4:53ef91c87d74 | 599 | |
charliex | 4:53ef91c87d74 | 600 | /*-------------------------------------------------------------------*/ |
charliex | 4:53ef91c87d74 | 601 | /* Next Scanline */ |
charliex | 4:53ef91c87d74 | 602 | /*-------------------------------------------------------------------*/ |
charliex | 4:53ef91c87d74 | 603 | PPU_Scanline = ( PPU_Scanline == SCAN_VBLANK_END ) ? 0 : PPU_Scanline + 1; |
charliex | 4:53ef91c87d74 | 604 | |
charliex | 4:53ef91c87d74 | 605 | /*-------------------------------------------------------------------*/ |
charliex | 4:53ef91c87d74 | 606 | /* Operation in the specific scanning line */ |
charliex | 4:53ef91c87d74 | 607 | /*-------------------------------------------------------------------*/ |
charliex | 4:53ef91c87d74 | 608 | switch ( PPU_Scanline ) |
charliex | 4:53ef91c87d74 | 609 | { |
charliex | 4:53ef91c87d74 | 610 | case SCAN_ON_SCREEN_START: |
charliex | 4:53ef91c87d74 | 611 | // Reset a PPU status |
charliex | 4:53ef91c87d74 | 612 | PPU_R2 = 0; |
charliex | 4:53ef91c87d74 | 613 | |
charliex | 4:53ef91c87d74 | 614 | // Set up a character data |
charliex | 4:53ef91c87d74 | 615 | if ( NesHeader.byVRomSize == 0 && FrameDraw ) |
charliex | 4:53ef91c87d74 | 616 | pNesX_SetupChr(); |
charliex | 4:53ef91c87d74 | 617 | |
charliex | 4:53ef91c87d74 | 618 | // Get position of sprite #0 |
charliex | 4:53ef91c87d74 | 619 | pNesX_GetSprHitY(); |
charliex | 4:53ef91c87d74 | 620 | break; |
charliex | 4:53ef91c87d74 | 621 | |
charliex | 4:53ef91c87d74 | 622 | case SCAN_VBLANK_START: |
charliex | 4:53ef91c87d74 | 623 | // Frame skip |
charliex | 4:53ef91c87d74 | 624 | FrameCnt = ++FrameCnt % 6; |
charliex | 4:53ef91c87d74 | 625 | switch (FrameSkip) |
charliex | 4:53ef91c87d74 | 626 | { |
charliex | 4:53ef91c87d74 | 627 | case 0: // full |
charliex | 4:53ef91c87d74 | 628 | FrameDraw = true; |
charliex | 4:53ef91c87d74 | 629 | break; |
charliex | 4:53ef91c87d74 | 630 | |
charliex | 4:53ef91c87d74 | 631 | case 1: // 1/2 |
charliex | 4:53ef91c87d74 | 632 | FrameDraw = FrameCnt & 1; |
charliex | 4:53ef91c87d74 | 633 | break; |
charliex | 4:53ef91c87d74 | 634 | |
charliex | 4:53ef91c87d74 | 635 | case 2: // 2/3 |
charliex | 4:53ef91c87d74 | 636 | FrameDraw = !(FrameCnt == 2 || FrameCnt == 5); |
charliex | 4:53ef91c87d74 | 637 | break; |
charliex | 4:53ef91c87d74 | 638 | |
charliex | 4:53ef91c87d74 | 639 | case 3: // 1/3 |
charliex | 4:53ef91c87d74 | 640 | FrameDraw = FrameCnt == 0 || FrameCnt == 3; |
charliex | 4:53ef91c87d74 | 641 | } |
charliex | 4:53ef91c87d74 | 642 | |
charliex | 4:53ef91c87d74 | 643 | pNesX_LoadFrame(); |
charliex | 4:53ef91c87d74 | 644 | |
charliex | 4:53ef91c87d74 | 645 | // Set a V-Blank flag |
charliex | 4:53ef91c87d74 | 646 | PPU_R2 = R2_IN_VBLANK; |
charliex | 4:53ef91c87d74 | 647 | |
charliex | 4:53ef91c87d74 | 648 | // Reset latch flag |
charliex | 4:53ef91c87d74 | 649 | PPU_Latch_Flag = 0; |
charliex | 4:53ef91c87d74 | 650 | |
charliex | 4:53ef91c87d74 | 651 | // A mapper function in V-Sync |
charliex | 4:53ef91c87d74 | 652 | MapperVSync(); |
charliex | 4:53ef91c87d74 | 653 | |
charliex | 4:53ef91c87d74 | 654 | // Get the condition of the joypad |
charliex | 4:53ef91c87d74 | 655 | pNesX_PadState( &PAD1_Latch, &PAD2_Latch, &PAD_System ); |
charliex | 4:53ef91c87d74 | 656 | |
charliex | 4:53ef91c87d74 | 657 | // NMI on V-Blank |
charliex | 4:53ef91c87d74 | 658 | if ( PPU_R0 & R0_NMI_VB ) |
charliex | 4:53ef91c87d74 | 659 | NMI_REQ; |
charliex | 4:53ef91c87d74 | 660 | |
charliex | 4:53ef91c87d74 | 661 | // Exit an emulation if a QUIT button is pushed |
charliex | 4:53ef91c87d74 | 662 | static DWORD quitWait; |
charliex | 4:53ef91c87d74 | 663 | if (PAD_PUSH( PAD_System, PAD_SYS_QUIT )) |
charliex | 4:53ef91c87d74 | 664 | { |
charliex | 4:53ef91c87d74 | 665 | quitWait++; |
charliex | 4:53ef91c87d74 | 666 | } |
charliex | 4:53ef91c87d74 | 667 | else |
charliex | 4:53ef91c87d74 | 668 | { |
charliex | 4:53ef91c87d74 | 669 | if (quitWait > 10) |
charliex | 4:53ef91c87d74 | 670 | { |
charliex | 4:53ef91c87d74 | 671 | quitWait = 0; |
charliex | 4:53ef91c87d74 | 672 | return -1; // Exit an emulation |
charliex | 4:53ef91c87d74 | 673 | } |
charliex | 4:53ef91c87d74 | 674 | quitWait = 0; |
charliex | 4:53ef91c87d74 | 675 | } |
charliex | 4:53ef91c87d74 | 676 | break; |
charliex | 4:53ef91c87d74 | 677 | |
charliex | 4:53ef91c87d74 | 678 | case SCAN_APU_CLK1: // 240Hz |
charliex | 4:53ef91c87d74 | 679 | case SCAN_APU_CLK3: // 240Hz |
charliex | 4:53ef91c87d74 | 680 | pNesX_ApuClk_240Hz(); |
charliex | 4:53ef91c87d74 | 681 | break; |
charliex | 4:53ef91c87d74 | 682 | |
charliex | 4:53ef91c87d74 | 683 | case SCAN_APU_CLK2: // 240Hz 120Hz |
charliex | 4:53ef91c87d74 | 684 | pNesX_ApuClk_240Hz(); |
charliex | 4:53ef91c87d74 | 685 | pNesX_ApuClk_120Hz(); |
charliex | 4:53ef91c87d74 | 686 | break; |
charliex | 4:53ef91c87d74 | 687 | |
charliex | 4:53ef91c87d74 | 688 | case SCAN_APU_CLK4: // 240Hz 120Hz 60Hz |
charliex | 4:53ef91c87d74 | 689 | pNesX_ApuClk_240Hz(); |
charliex | 4:53ef91c87d74 | 690 | pNesX_ApuClk_120Hz(); |
charliex | 4:53ef91c87d74 | 691 | pNesX_ApuClk_60Hz(); |
charliex | 4:53ef91c87d74 | 692 | break; |
charliex | 4:53ef91c87d74 | 693 | |
charliex | 4:53ef91c87d74 | 694 | } |
charliex | 4:53ef91c87d74 | 695 | |
charliex | 4:53ef91c87d74 | 696 | // Successful |
charliex | 4:53ef91c87d74 | 697 | return 0; |
charliex | 4:53ef91c87d74 | 698 | } |
charliex | 4:53ef91c87d74 | 699 | |
charliex | 4:53ef91c87d74 | 700 | /*===================================================================*/ |
charliex | 4:53ef91c87d74 | 701 | /* */ |
charliex | 4:53ef91c87d74 | 702 | /* pNesX_DrawLine() : Render a scanline */ |
charliex | 4:53ef91c87d74 | 703 | /* */ |
charliex | 4:53ef91c87d74 | 704 | /*===================================================================*/ |
charliex | 4:53ef91c87d74 | 705 | |
charliex | 4:53ef91c87d74 | 706 | |
charliex | 4:53ef91c87d74 | 707 | void pNesX_DrawLine() |
charliex | 4:53ef91c87d74 | 708 | { |
charliex | 4:53ef91c87d74 | 709 | /* |
charliex | 4:53ef91c87d74 | 710 | * Render a scanline |
charliex | 4:53ef91c87d74 | 711 | * |
charliex | 4:53ef91c87d74 | 712 | */ |
charliex | 4:53ef91c87d74 | 713 | int nX; |
charliex | 4:53ef91c87d74 | 714 | int nY; |
charliex | 4:53ef91c87d74 | 715 | int nY4; |
charliex | 4:53ef91c87d74 | 716 | int nYBit; |
charliex | 4:53ef91c87d74 | 717 | WORD *pPalTbl; |
charliex | 4:53ef91c87d74 | 718 | BYTE *pAttrBase; |
charliex | 4:53ef91c87d74 | 719 | WORD *pPoint; |
charliex | 4:53ef91c87d74 | 720 | int nNameTable; |
charliex | 4:53ef91c87d74 | 721 | BYTE *pbyNameTable; |
charliex | 4:53ef91c87d74 | 722 | BYTE *pbyChrData; |
charliex | 4:53ef91c87d74 | 723 | BYTE *pSPRRAM; |
charliex | 4:53ef91c87d74 | 724 | int nAttr; |
charliex | 4:53ef91c87d74 | 725 | int nSprCnt; |
charliex | 4:53ef91c87d74 | 726 | int nIdx; |
charliex | 4:53ef91c87d74 | 727 | BYTE bySprCol; |
charliex | 4:53ef91c87d74 | 728 | bool bMask[ NES_DISP_WIDTH ]; |
charliex | 4:53ef91c87d74 | 729 | bool *pMask; |
charliex | 4:53ef91c87d74 | 730 | |
charliex | 4:53ef91c87d74 | 731 | // Pointer to the render position |
charliex | 4:53ef91c87d74 | 732 | pPoint = LineData[LineDataIdx]; |
charliex | 4:53ef91c87d74 | 733 | LineDataIdx = LineDataIdx == 0 ? 1 : 0; |
charliex | 4:53ef91c87d74 | 734 | pDrawData = pPoint; |
charliex | 4:53ef91c87d74 | 735 | |
charliex | 4:53ef91c87d74 | 736 | // Clear a scanline if screen is off |
charliex | 4:53ef91c87d74 | 737 | if ( !( PPU_R1 & R1_SHOW_SCR ) ) |
charliex | 4:53ef91c87d74 | 738 | { |
charliex | 4:53ef91c87d74 | 739 | pNesX_MemorySet( pPoint, 0, NES_DISP_WIDTH << 1 ); |
charliex | 4:53ef91c87d74 | 740 | return; |
charliex | 4:53ef91c87d74 | 741 | } |
charliex | 4:53ef91c87d74 | 742 | |
charliex | 4:53ef91c87d74 | 743 | nNameTable = PPU_NameTableBank; |
charliex | 4:53ef91c87d74 | 744 | |
charliex | 4:53ef91c87d74 | 745 | nY = PPU_Scr_V_Byte + ( PPU_Scanline >> 3 ); |
charliex | 4:53ef91c87d74 | 746 | |
charliex | 4:53ef91c87d74 | 747 | nYBit = PPU_Scr_V_Bit + ( PPU_Scanline & 7 ); |
charliex | 4:53ef91c87d74 | 748 | |
charliex | 4:53ef91c87d74 | 749 | if ( nYBit > 7 ) |
charliex | 4:53ef91c87d74 | 750 | { |
charliex | 4:53ef91c87d74 | 751 | ++nY; |
charliex | 4:53ef91c87d74 | 752 | nYBit &= 7; |
charliex | 4:53ef91c87d74 | 753 | } |
charliex | 4:53ef91c87d74 | 754 | nYBit <<= 3; |
charliex | 4:53ef91c87d74 | 755 | |
charliex | 4:53ef91c87d74 | 756 | if ( nY > 29 ) |
charliex | 4:53ef91c87d74 | 757 | { |
charliex | 4:53ef91c87d74 | 758 | // Next NameTable (An up-down direction) |
charliex | 4:53ef91c87d74 | 759 | nNameTable ^= NAME_TABLE_V_MASK; |
charliex | 4:53ef91c87d74 | 760 | nY -= 30; |
charliex | 4:53ef91c87d74 | 761 | } |
charliex | 4:53ef91c87d74 | 762 | |
charliex | 4:53ef91c87d74 | 763 | nX = PPU_Scr_H_Byte; |
charliex | 4:53ef91c87d74 | 764 | |
charliex | 4:53ef91c87d74 | 765 | nY4 = ( ( nY & 2 ) << 1 ); |
charliex | 4:53ef91c87d74 | 766 | |
charliex | 4:53ef91c87d74 | 767 | pMask = bMask; |
charliex | 4:53ef91c87d74 | 768 | |
charliex | 4:53ef91c87d74 | 769 | /*-------------------------------------------------------------------*/ |
charliex | 4:53ef91c87d74 | 770 | /* Rendering of the block of the left end */ |
charliex | 4:53ef91c87d74 | 771 | /*-------------------------------------------------------------------*/ |
charliex | 4:53ef91c87d74 | 772 | |
charliex | 4:53ef91c87d74 | 773 | pbyNameTable = PPUBANK[ nNameTable ] + nY * 32 + nX; |
charliex | 4:53ef91c87d74 | 774 | pbyChrData = PPU_BG_Base + ( *pbyNameTable << 6 ) + nYBit; |
charliex | 4:53ef91c87d74 | 775 | pAttrBase = PPUBANK[ nNameTable ] + 0x3c0 + ( nY / 4 ) * 8; |
charliex | 4:53ef91c87d74 | 776 | pPalTbl = &PalTable[ ( ( ( pAttrBase[ nX >> 2 ] >> ( ( nX & 2 ) + nY4 ) ) & 3 ) << 2 ) ]; |
charliex | 4:53ef91c87d74 | 777 | |
charliex | 4:53ef91c87d74 | 778 | for ( nIdx = PPU_Scr_H_Bit; nIdx < 8; ++nIdx ) |
charliex | 4:53ef91c87d74 | 779 | { |
charliex | 4:53ef91c87d74 | 780 | *( pPoint++ ) = pPalTbl[ pbyChrData[ nIdx ] ]; |
charliex | 4:53ef91c87d74 | 781 | *pMask++ = pbyChrData[ nIdx ] == 0; |
charliex | 4:53ef91c87d74 | 782 | } |
charliex | 4:53ef91c87d74 | 783 | |
charliex | 4:53ef91c87d74 | 784 | ++nX; |
charliex | 4:53ef91c87d74 | 785 | ++pbyNameTable; |
charliex | 4:53ef91c87d74 | 786 | |
charliex | 4:53ef91c87d74 | 787 | /*-------------------------------------------------------------------*/ |
charliex | 4:53ef91c87d74 | 788 | /* Rendering of the left table */ |
charliex | 4:53ef91c87d74 | 789 | /*-------------------------------------------------------------------*/ |
charliex | 4:53ef91c87d74 | 790 | |
charliex | 4:53ef91c87d74 | 791 | for ( ; nX < 32; ++nX ) |
charliex | 4:53ef91c87d74 | 792 | { |
charliex | 4:53ef91c87d74 | 793 | pbyChrData = PPU_BG_Base + ( *pbyNameTable << 6 ) + nYBit; |
charliex | 4:53ef91c87d74 | 794 | pPalTbl = &PalTable[ ( ( ( pAttrBase[ nX >> 2 ] >> ( ( nX & 2 ) + nY4 ) ) & 3 ) << 2 ) ]; |
charliex | 4:53ef91c87d74 | 795 | |
charliex | 4:53ef91c87d74 | 796 | *pPoint++ = pPalTbl[ pbyChrData[ 0 ] ]; |
charliex | 4:53ef91c87d74 | 797 | *pPoint++ = pPalTbl[ pbyChrData[ 1 ] ]; |
charliex | 4:53ef91c87d74 | 798 | *pPoint++ = pPalTbl[ pbyChrData[ 2 ] ]; |
charliex | 4:53ef91c87d74 | 799 | *pPoint++ = pPalTbl[ pbyChrData[ 3 ] ]; |
charliex | 4:53ef91c87d74 | 800 | *pPoint++ = pPalTbl[ pbyChrData[ 4 ] ]; |
charliex | 4:53ef91c87d74 | 801 | *pPoint++ = pPalTbl[ pbyChrData[ 5 ] ]; |
charliex | 4:53ef91c87d74 | 802 | *pPoint++ = pPalTbl[ pbyChrData[ 6 ] ]; |
charliex | 4:53ef91c87d74 | 803 | *pPoint++ = pPalTbl[ pbyChrData[ 7 ] ]; |
charliex | 4:53ef91c87d74 | 804 | |
charliex | 4:53ef91c87d74 | 805 | *pMask++ = pbyChrData[ 0 ] == 0; |
charliex | 4:53ef91c87d74 | 806 | *pMask++ = pbyChrData[ 1 ] == 0; |
charliex | 4:53ef91c87d74 | 807 | *pMask++ = pbyChrData[ 2 ] == 0; |
charliex | 4:53ef91c87d74 | 808 | *pMask++ = pbyChrData[ 3 ] == 0; |
charliex | 4:53ef91c87d74 | 809 | *pMask++ = pbyChrData[ 4 ] == 0; |
charliex | 4:53ef91c87d74 | 810 | *pMask++ = pbyChrData[ 5 ] == 0; |
charliex | 4:53ef91c87d74 | 811 | *pMask++ = pbyChrData[ 6 ] == 0; |
charliex | 4:53ef91c87d74 | 812 | *pMask++ = pbyChrData[ 7 ] == 0; |
charliex | 4:53ef91c87d74 | 813 | |
charliex | 4:53ef91c87d74 | 814 | ++pbyNameTable; |
charliex | 4:53ef91c87d74 | 815 | } |
charliex | 4:53ef91c87d74 | 816 | |
charliex | 4:53ef91c87d74 | 817 | // Holizontal Mirror |
charliex | 4:53ef91c87d74 | 818 | nNameTable ^= NAME_TABLE_H_MASK; |
charliex | 4:53ef91c87d74 | 819 | |
charliex | 4:53ef91c87d74 | 820 | pbyNameTable = PPUBANK[ nNameTable ] + nY * 32; |
charliex | 4:53ef91c87d74 | 821 | pAttrBase = PPUBANK[ nNameTable ] + 0x3c0 + ( nY / 4 ) * 8; |
charliex | 4:53ef91c87d74 | 822 | |
charliex | 4:53ef91c87d74 | 823 | /*-------------------------------------------------------------------*/ |
charliex | 4:53ef91c87d74 | 824 | /* Rendering of the right table */ |
charliex | 4:53ef91c87d74 | 825 | /*-------------------------------------------------------------------*/ |
charliex | 4:53ef91c87d74 | 826 | |
charliex | 4:53ef91c87d74 | 827 | for ( nX = 0; nX < PPU_Scr_H_Byte; ++nX ) |
charliex | 4:53ef91c87d74 | 828 | { |
charliex | 4:53ef91c87d74 | 829 | pbyChrData = PPU_BG_Base + ( *pbyNameTable << 6 ) + nYBit; |
charliex | 4:53ef91c87d74 | 830 | pPalTbl = &PalTable[ ( ( ( pAttrBase[ nX >> 2 ] >> ( ( nX & 2 ) + nY4 ) ) & 3 ) << 2 ) ]; |
charliex | 4:53ef91c87d74 | 831 | |
charliex | 4:53ef91c87d74 | 832 | *pPoint++ = pPalTbl[ pbyChrData[ 0 ] ]; |
charliex | 4:53ef91c87d74 | 833 | *pPoint++ = pPalTbl[ pbyChrData[ 1 ] ]; |
charliex | 4:53ef91c87d74 | 834 | *pPoint++ = pPalTbl[ pbyChrData[ 2 ] ]; |
charliex | 4:53ef91c87d74 | 835 | *pPoint++ = pPalTbl[ pbyChrData[ 3 ] ]; |
charliex | 4:53ef91c87d74 | 836 | *pPoint++ = pPalTbl[ pbyChrData[ 4 ] ]; |
charliex | 4:53ef91c87d74 | 837 | *pPoint++ = pPalTbl[ pbyChrData[ 5 ] ]; |
charliex | 4:53ef91c87d74 | 838 | *pPoint++ = pPalTbl[ pbyChrData[ 6 ] ]; |
charliex | 4:53ef91c87d74 | 839 | *pPoint++ = pPalTbl[ pbyChrData[ 7 ] ]; |
charliex | 4:53ef91c87d74 | 840 | |
charliex | 4:53ef91c87d74 | 841 | *pMask++ = pbyChrData[ 0 ] == 0; |
charliex | 4:53ef91c87d74 | 842 | *pMask++ = pbyChrData[ 1 ] == 0; |
charliex | 4:53ef91c87d74 | 843 | *pMask++ = pbyChrData[ 2 ] == 0; |
charliex | 4:53ef91c87d74 | 844 | *pMask++ = pbyChrData[ 3 ] == 0; |
charliex | 4:53ef91c87d74 | 845 | *pMask++ = pbyChrData[ 4 ] == 0; |
charliex | 4:53ef91c87d74 | 846 | *pMask++ = pbyChrData[ 5 ] == 0; |
charliex | 4:53ef91c87d74 | 847 | *pMask++ = pbyChrData[ 6 ] == 0; |
charliex | 4:53ef91c87d74 | 848 | *pMask++ = pbyChrData[ 7 ] == 0; |
charliex | 4:53ef91c87d74 | 849 | |
charliex | 4:53ef91c87d74 | 850 | ++pbyNameTable; |
charliex | 4:53ef91c87d74 | 851 | } |
charliex | 4:53ef91c87d74 | 852 | |
charliex | 4:53ef91c87d74 | 853 | /*-------------------------------------------------------------------*/ |
charliex | 4:53ef91c87d74 | 854 | /* Rendering of the block of the right end */ |
charliex | 4:53ef91c87d74 | 855 | /*-------------------------------------------------------------------*/ |
charliex | 4:53ef91c87d74 | 856 | |
charliex | 4:53ef91c87d74 | 857 | pbyChrData = PPU_BG_Base + ( *pbyNameTable << 6 ) + nYBit; |
charliex | 4:53ef91c87d74 | 858 | pPalTbl = &PalTable[ ( ( ( pAttrBase[ nX >> 2 ] >> ( ( nX & 2 ) + nY4 ) ) & 3 ) << 2 ) ]; |
charliex | 4:53ef91c87d74 | 859 | for ( nIdx = 0; nIdx < PPU_Scr_H_Bit; ++nIdx ) |
charliex | 4:53ef91c87d74 | 860 | { |
charliex | 4:53ef91c87d74 | 861 | pPoint[ nIdx ] = pPalTbl[ pbyChrData[ nIdx ] ]; |
charliex | 4:53ef91c87d74 | 862 | *pMask++ = pbyChrData[ nIdx ] == 0; |
charliex | 4:53ef91c87d74 | 863 | } |
charliex | 4:53ef91c87d74 | 864 | |
charliex | 4:53ef91c87d74 | 865 | /*-------------------------------------------------------------------*/ |
charliex | 4:53ef91c87d74 | 866 | /* Render a sprite */ |
charliex | 4:53ef91c87d74 | 867 | /*-------------------------------------------------------------------*/ |
charliex | 4:53ef91c87d74 | 868 | |
charliex | 4:53ef91c87d74 | 869 | if ( PPU_R1 & R1_SHOW_SP ) |
charliex | 4:53ef91c87d74 | 870 | { |
charliex | 4:53ef91c87d74 | 871 | // Reset Scanline Sprite Count |
charliex | 4:53ef91c87d74 | 872 | PPU_R2 &= ~R2_MAX_SP; |
charliex | 4:53ef91c87d74 | 873 | |
charliex | 4:53ef91c87d74 | 874 | // Render a sprite to the sprite buffer |
charliex | 4:53ef91c87d74 | 875 | pPoint = pDrawData; |
charliex | 4:53ef91c87d74 | 876 | nSprCnt = 0; |
charliex | 4:53ef91c87d74 | 877 | for ( pSPRRAM = SPRRAM + ( 63 << 2 ); pSPRRAM >= SPRRAM && |
charliex | 4:53ef91c87d74 | 878 | nSprCnt < 8; pSPRRAM -= 4 ) |
charliex | 4:53ef91c87d74 | 879 | { |
charliex | 4:53ef91c87d74 | 880 | nY = pSPRRAM[ SPR_Y ] + 1; |
charliex | 4:53ef91c87d74 | 881 | if ( nY > PPU_Scanline || nY + PPU_SP_Height <= PPU_Scanline ) |
charliex | 4:53ef91c87d74 | 882 | continue; // Next sprite |
charliex | 4:53ef91c87d74 | 883 | |
charliex | 4:53ef91c87d74 | 884 | /*-------------------------------------------------------------------*/ |
charliex | 4:53ef91c87d74 | 885 | /* A sprite in scanning line */ |
charliex | 4:53ef91c87d74 | 886 | /*-------------------------------------------------------------------*/ |
charliex | 4:53ef91c87d74 | 887 | |
charliex | 4:53ef91c87d74 | 888 | // Holizontal Sprite Count +1 |
charliex | 4:53ef91c87d74 | 889 | ++nSprCnt; |
charliex | 4:53ef91c87d74 | 890 | |
charliex | 4:53ef91c87d74 | 891 | nAttr = pSPRRAM[ SPR_ATTR ]; |
charliex | 4:53ef91c87d74 | 892 | nYBit = PPU_Scanline - nY; |
charliex | 4:53ef91c87d74 | 893 | nYBit = ( nAttr & SPR_ATTR_V_FLIP ) ? ( PPU_SP_Height - nYBit - 1 ) << 3 : nYBit << 3; |
charliex | 4:53ef91c87d74 | 894 | |
charliex | 4:53ef91c87d74 | 895 | if ( PPU_R0 & R0_SP_SIZE ) |
charliex | 4:53ef91c87d74 | 896 | { |
charliex | 4:53ef91c87d74 | 897 | // Sprite size 8x16 |
charliex | 4:53ef91c87d74 | 898 | if ( pSPRRAM[ SPR_CHR ] & 1 ) |
charliex | 4:53ef91c87d74 | 899 | { |
charliex | 4:53ef91c87d74 | 900 | pbyChrData = ChrBuf + 256 * 64 + ( ( pSPRRAM[ SPR_CHR ] & 0xfe ) << 6 ) + nYBit; |
charliex | 4:53ef91c87d74 | 901 | } |
charliex | 4:53ef91c87d74 | 902 | else |
charliex | 4:53ef91c87d74 | 903 | { |
charliex | 4:53ef91c87d74 | 904 | pbyChrData = ChrBuf + ( ( pSPRRAM[ SPR_CHR ] & 0xfe ) << 6 ) + nYBit; |
charliex | 4:53ef91c87d74 | 905 | } |
charliex | 4:53ef91c87d74 | 906 | } |
charliex | 4:53ef91c87d74 | 907 | else |
charliex | 4:53ef91c87d74 | 908 | { |
charliex | 4:53ef91c87d74 | 909 | // Sprite size 8x8 |
charliex | 4:53ef91c87d74 | 910 | pbyChrData = PPU_SP_Base + ( pSPRRAM[ SPR_CHR ] << 6 ) + nYBit; |
charliex | 4:53ef91c87d74 | 911 | } |
charliex | 4:53ef91c87d74 | 912 | |
charliex | 4:53ef91c87d74 | 913 | bool bSprFront = !(nAttr & SPR_ATTR_PRI); |
charliex | 4:53ef91c87d74 | 914 | bySprCol = (( nAttr & SPR_ATTR_COLOR ) << 2) + 0x10; |
charliex | 4:53ef91c87d74 | 915 | nX = pSPRRAM[ SPR_X ]; |
charliex | 4:53ef91c87d74 | 916 | |
charliex | 4:53ef91c87d74 | 917 | if ( nAttr & SPR_ATTR_H_FLIP ) |
charliex | 4:53ef91c87d74 | 918 | { |
charliex | 4:53ef91c87d74 | 919 | // Horizontal flip |
charliex | 4:53ef91c87d74 | 920 | if ( pbyChrData[ 0 ] && nX < 249 && (bSprFront || bMask[nX + 7]) ) |
charliex | 4:53ef91c87d74 | 921 | pPoint[ nX + 7 ] = PalTable[ bySprCol | pbyChrData[ 0 ] ]; |
charliex | 4:53ef91c87d74 | 922 | if ( pbyChrData[ 1 ] && nX < 250 && (bSprFront || bMask[nX + 6]) ) |
charliex | 4:53ef91c87d74 | 923 | pPoint[ nX + 6 ] = PalTable[ bySprCol | pbyChrData[ 1 ] ]; |
charliex | 4:53ef91c87d74 | 924 | if ( pbyChrData[ 2 ] && nX < 251 && (bSprFront || bMask[nX + 5]) ) |
charliex | 4:53ef91c87d74 | 925 | pPoint[ nX + 5 ] = PalTable[ bySprCol | pbyChrData[ 2 ] ]; |
charliex | 4:53ef91c87d74 | 926 | if ( pbyChrData[ 3 ] && nX < 252 && (bSprFront || bMask[nX + 4]) ) |
charliex | 4:53ef91c87d74 | 927 | pPoint[ nX + 4 ] = PalTable[ bySprCol | pbyChrData[ 3 ] ]; |
charliex | 4:53ef91c87d74 | 928 | if ( pbyChrData[ 4 ] && nX < 253 && (bSprFront || bMask[nX + 3]) ) |
charliex | 4:53ef91c87d74 | 929 | pPoint[ nX + 3 ] = PalTable[ bySprCol | pbyChrData[ 4 ] ]; |
charliex | 4:53ef91c87d74 | 930 | if ( pbyChrData[ 5 ] && nX < 254 && (bSprFront || bMask[nX + 2]) ) |
charliex | 4:53ef91c87d74 | 931 | pPoint[ nX + 2 ] = PalTable[ bySprCol | pbyChrData[ 5 ] ]; |
charliex | 4:53ef91c87d74 | 932 | if ( pbyChrData[ 6 ] && nX < 255 && (bSprFront || bMask[nX + 1]) ) |
charliex | 4:53ef91c87d74 | 933 | pPoint[ nX + 1 ] = PalTable[ bySprCol | pbyChrData[ 6 ] ]; |
charliex | 4:53ef91c87d74 | 934 | if ( pbyChrData[ 7 ] && (bSprFront || bMask[nX]) ) |
charliex | 4:53ef91c87d74 | 935 | pPoint[ nX ] = PalTable[ bySprCol | pbyChrData[ 7 ] ]; |
charliex | 4:53ef91c87d74 | 936 | } |
charliex | 4:53ef91c87d74 | 937 | else |
charliex | 4:53ef91c87d74 | 938 | { |
charliex | 4:53ef91c87d74 | 939 | // Non flip |
charliex | 4:53ef91c87d74 | 940 | if ( pbyChrData[ 0 ] && (bSprFront || bMask[nX]) ) |
charliex | 4:53ef91c87d74 | 941 | pPoint[ nX ] = PalTable[ bySprCol | pbyChrData[ 0 ] ]; |
charliex | 4:53ef91c87d74 | 942 | if ( pbyChrData[ 1 ] && nX < 255 && (bSprFront || bMask[nX + 1]) ) |
charliex | 4:53ef91c87d74 | 943 | pPoint[ nX + 1 ] = PalTable[ bySprCol | pbyChrData[ 1 ] ]; |
charliex | 4:53ef91c87d74 | 944 | if ( pbyChrData[ 2 ] && nX < 254 && (bSprFront || bMask[nX + 2]) ) |
charliex | 4:53ef91c87d74 | 945 | pPoint[ nX + 2 ] = PalTable[ bySprCol | pbyChrData[ 2 ] ]; |
charliex | 4:53ef91c87d74 | 946 | if ( pbyChrData[ 3 ] && nX < 253 && (bSprFront || bMask[nX + 3]) ) |
charliex | 4:53ef91c87d74 | 947 | pPoint[ nX + 3 ] = PalTable[ bySprCol | pbyChrData[ 3 ] ]; |
charliex | 4:53ef91c87d74 | 948 | if ( pbyChrData[ 4 ] && nX < 252 && (bSprFront || bMask[nX + 4]) ) |
charliex | 4:53ef91c87d74 | 949 | pPoint[ nX + 4 ] = PalTable[ bySprCol | pbyChrData[ 4 ] ]; |
charliex | 4:53ef91c87d74 | 950 | if ( pbyChrData[ 5 ] && nX < 251 && (bSprFront || bMask[nX + 5]) ) |
charliex | 4:53ef91c87d74 | 951 | pPoint[ nX + 5 ] = PalTable[ bySprCol | pbyChrData[ 5 ] ]; |
charliex | 4:53ef91c87d74 | 952 | if ( pbyChrData[ 6 ] && nX < 250 && (bSprFront || bMask[nX + 6]) ) |
charliex | 4:53ef91c87d74 | 953 | pPoint[ nX + 6 ] = PalTable[ bySprCol | pbyChrData[ 6 ] ]; |
charliex | 4:53ef91c87d74 | 954 | if ( pbyChrData[ 7 ] && nX < 249 && (bSprFront || bMask[nX + 7]) ) |
charliex | 4:53ef91c87d74 | 955 | pPoint[ nX + 7 ] = PalTable[ bySprCol | pbyChrData[ 7 ] ]; |
charliex | 4:53ef91c87d74 | 956 | } |
charliex | 4:53ef91c87d74 | 957 | } |
charliex | 4:53ef91c87d74 | 958 | |
charliex | 4:53ef91c87d74 | 959 | if ( nSprCnt == 8 ) |
charliex | 4:53ef91c87d74 | 960 | PPU_R2 |= R2_MAX_SP; // Set a flag of maximum sprites on scanline |
charliex | 4:53ef91c87d74 | 961 | } |
charliex | 4:53ef91c87d74 | 962 | } |
charliex | 4:53ef91c87d74 | 963 | |
charliex | 4:53ef91c87d74 | 964 | /*===================================================================*/ |
charliex | 4:53ef91c87d74 | 965 | /* */ |
charliex | 4:53ef91c87d74 | 966 | /* pNesX_GetSprHitY() : Get a position of scanline hits sprite #0 */ |
charliex | 4:53ef91c87d74 | 967 | /* */ |
charliex | 4:53ef91c87d74 | 968 | /*===================================================================*/ |
charliex | 4:53ef91c87d74 | 969 | void pNesX_GetSprHitY() |
charliex | 4:53ef91c87d74 | 970 | { |
charliex | 4:53ef91c87d74 | 971 | /* |
charliex | 4:53ef91c87d74 | 972 | * Get a position of scanline hits sprite #0 |
charliex | 4:53ef91c87d74 | 973 | * |
charliex | 4:53ef91c87d74 | 974 | */ |
charliex | 4:53ef91c87d74 | 975 | |
charliex | 4:53ef91c87d74 | 976 | int nYBit; |
charliex | 4:53ef91c87d74 | 977 | DWORD *pdwChrData; |
charliex | 4:53ef91c87d74 | 978 | int nOff; |
charliex | 4:53ef91c87d74 | 979 | |
charliex | 4:53ef91c87d74 | 980 | if ( SPRRAM[ SPR_ATTR ] & SPR_ATTR_V_FLIP ) |
charliex | 4:53ef91c87d74 | 981 | { |
charliex | 4:53ef91c87d74 | 982 | // Vertical flip |
charliex | 4:53ef91c87d74 | 983 | nYBit = ( PPU_SP_Height - 1 ) << 3; |
charliex | 4:53ef91c87d74 | 984 | nOff = -2; |
charliex | 4:53ef91c87d74 | 985 | } |
charliex | 4:53ef91c87d74 | 986 | else |
charliex | 4:53ef91c87d74 | 987 | { |
charliex | 4:53ef91c87d74 | 988 | // Non flip |
charliex | 4:53ef91c87d74 | 989 | nYBit = 0; |
charliex | 4:53ef91c87d74 | 990 | nOff = 2; |
charliex | 4:53ef91c87d74 | 991 | } |
charliex | 4:53ef91c87d74 | 992 | |
charliex | 4:53ef91c87d74 | 993 | if ( PPU_R0 & R0_SP_SIZE ) |
charliex | 4:53ef91c87d74 | 994 | { |
charliex | 4:53ef91c87d74 | 995 | // Sprite size 8x16 |
charliex | 4:53ef91c87d74 | 996 | if ( SPRRAM[ SPR_CHR ] & 1 ) |
charliex | 4:53ef91c87d74 | 997 | { |
charliex | 4:53ef91c87d74 | 998 | pdwChrData = (DWORD *)( ChrBuf + 256 * 64 + ( ( SPRRAM[ SPR_CHR ] & 0xfe ) << 6 ) + nYBit ); |
charliex | 4:53ef91c87d74 | 999 | } |
charliex | 4:53ef91c87d74 | 1000 | else |
charliex | 4:53ef91c87d74 | 1001 | { |
charliex | 4:53ef91c87d74 | 1002 | pdwChrData = (DWORD * )( ChrBuf + ( ( SPRRAM[ SPR_CHR ] & 0xfe ) << 6 ) + nYBit ); |
charliex | 4:53ef91c87d74 | 1003 | } |
charliex | 4:53ef91c87d74 | 1004 | } |
charliex | 4:53ef91c87d74 | 1005 | else |
charliex | 4:53ef91c87d74 | 1006 | { |
charliex | 4:53ef91c87d74 | 1007 | // Sprite size 8x8 |
charliex | 4:53ef91c87d74 | 1008 | pdwChrData = (DWORD *)( PPU_SP_Base + ( SPRRAM[ SPR_CHR ] << 6 ) + nYBit ); |
charliex | 4:53ef91c87d74 | 1009 | } |
charliex | 4:53ef91c87d74 | 1010 | |
charliex | 4:53ef91c87d74 | 1011 | for ( SpriteHitPos = 1; SpriteHitPos < PPU_SP_Height + 1; ++SpriteHitPos ) |
charliex | 4:53ef91c87d74 | 1012 | { |
charliex | 4:53ef91c87d74 | 1013 | if ( pdwChrData[ 0 ] | pdwChrData[ 1 ] ) |
charliex | 4:53ef91c87d74 | 1014 | return; // Scanline hits sprite #0 |
charliex | 4:53ef91c87d74 | 1015 | |
charliex | 4:53ef91c87d74 | 1016 | pdwChrData += nOff; |
charliex | 4:53ef91c87d74 | 1017 | } |
charliex | 4:53ef91c87d74 | 1018 | |
charliex | 4:53ef91c87d74 | 1019 | // Scanline didn't hit sprite #0 |
charliex | 4:53ef91c87d74 | 1020 | SpriteHitPos = SCAN_VBLANK_END; |
charliex | 4:53ef91c87d74 | 1021 | } |
charliex | 4:53ef91c87d74 | 1022 | |
charliex | 4:53ef91c87d74 | 1023 | /*===================================================================*/ |
charliex | 4:53ef91c87d74 | 1024 | /* */ |
charliex | 4:53ef91c87d74 | 1025 | /* pNesX_SetupChr() : Develop character data */ |
charliex | 4:53ef91c87d74 | 1026 | /* */ |
charliex | 4:53ef91c87d74 | 1027 | /*===================================================================*/ |
charliex | 4:53ef91c87d74 | 1028 | void pNesX_SetupChr() |
charliex | 4:53ef91c87d74 | 1029 | { |
charliex | 4:53ef91c87d74 | 1030 | /* |
charliex | 4:53ef91c87d74 | 1031 | * Develop character data |
charliex | 4:53ef91c87d74 | 1032 | * |
charliex | 4:53ef91c87d74 | 1033 | */ |
charliex | 4:53ef91c87d74 | 1034 | |
charliex | 4:53ef91c87d74 | 1035 | BYTE *pbyBGData; |
charliex | 4:53ef91c87d74 | 1036 | BYTE byData1; |
charliex | 4:53ef91c87d74 | 1037 | BYTE byData2; |
charliex | 4:53ef91c87d74 | 1038 | int nIdx; |
charliex | 4:53ef91c87d74 | 1039 | int nY; |
charliex | 4:53ef91c87d74 | 1040 | int nOff; |
charliex | 4:53ef91c87d74 | 1041 | static BYTE *pbyPrevBank[ 8 ]; |
charliex | 4:53ef91c87d74 | 1042 | int nBank; |
charliex | 4:53ef91c87d74 | 1043 | |
charliex | 4:53ef91c87d74 | 1044 | for ( nBank = 0; nBank < 8; ++nBank ) |
charliex | 4:53ef91c87d74 | 1045 | { |
charliex | 4:53ef91c87d74 | 1046 | if ( pbyPrevBank[ nBank ] == PPUBANK[ nBank ] && !( ( ChrBufUpdate >> nBank ) & 1 ) ) |
charliex | 4:53ef91c87d74 | 1047 | continue; // Next bank |
charliex | 4:53ef91c87d74 | 1048 | |
charliex | 4:53ef91c87d74 | 1049 | /*-------------------------------------------------------------------*/ |
charliex | 4:53ef91c87d74 | 1050 | /* An address is different from the last time */ |
charliex | 4:53ef91c87d74 | 1051 | /* or */ |
charliex | 4:53ef91c87d74 | 1052 | /* An update flag is being set */ |
charliex | 4:53ef91c87d74 | 1053 | /*-------------------------------------------------------------------*/ |
charliex | 4:53ef91c87d74 | 1054 | |
charliex | 4:53ef91c87d74 | 1055 | for ( nIdx = 0; nIdx < 64; ++nIdx ) |
charliex | 4:53ef91c87d74 | 1056 | { |
charliex | 4:53ef91c87d74 | 1057 | nOff = ( nBank << 12 ) + ( nIdx << 6 ); |
charliex | 4:53ef91c87d74 | 1058 | |
charliex | 4:53ef91c87d74 | 1059 | for ( nY = 0; nY < 8; ++nY ) |
charliex | 4:53ef91c87d74 | 1060 | { |
charliex | 4:53ef91c87d74 | 1061 | pbyBGData = PPUBANK[ nBank ] + ( nIdx << 4 ) + nY; |
charliex | 4:53ef91c87d74 | 1062 | |
charliex | 4:53ef91c87d74 | 1063 | byData1 = ( ( pbyBGData[ 0 ] >> 1 ) & 0x55 ) | ( pbyBGData[ 8 ] & 0xAA ); |
charliex | 4:53ef91c87d74 | 1064 | byData2 = ( pbyBGData[ 0 ] & 0x55 ) | ( ( pbyBGData[ 8 ] << 1 ) & 0xAA ); |
charliex | 4:53ef91c87d74 | 1065 | |
charliex | 4:53ef91c87d74 | 1066 | ChrBuf[ nOff++ ] = ( byData1 >> 6 ) & 3; |
charliex | 4:53ef91c87d74 | 1067 | ChrBuf[ nOff++ ] = ( byData2 >> 6 ) & 3; |
charliex | 4:53ef91c87d74 | 1068 | ChrBuf[ nOff++ ] = ( byData1 >> 4 ) & 3; |
charliex | 4:53ef91c87d74 | 1069 | ChrBuf[ nOff++ ] = ( byData2 >> 4 ) & 3; |
charliex | 4:53ef91c87d74 | 1070 | ChrBuf[ nOff++ ] = ( byData1 >> 2 ) & 3; |
charliex | 4:53ef91c87d74 | 1071 | ChrBuf[ nOff++ ] = ( byData2 >> 2 ) & 3; |
charliex | 4:53ef91c87d74 | 1072 | ChrBuf[ nOff++ ] = byData1 & 3; |
charliex | 4:53ef91c87d74 | 1073 | ChrBuf[ nOff++ ] = byData2 & 3; |
charliex | 4:53ef91c87d74 | 1074 | } |
charliex | 4:53ef91c87d74 | 1075 | } |
charliex | 4:53ef91c87d74 | 1076 | // Keep this address |
charliex | 4:53ef91c87d74 | 1077 | pbyPrevBank[ nBank ] = PPUBANK[ nBank ]; |
charliex | 4:53ef91c87d74 | 1078 | } |
charliex | 4:53ef91c87d74 | 1079 | |
charliex | 4:53ef91c87d74 | 1080 | // Reset update flag |
charliex | 4:53ef91c87d74 | 1081 | ChrBufUpdate = 0; |
charliex | 4:53ef91c87d74 | 1082 | } |
charliex | 4:53ef91c87d74 | 1083 |