I have ported my old project “pNesX” game console emulator to the nucleo.

Dependencies:   SDFileSystem mbed

Intro

I have ported my old project “pNesX” to the STM32 Nucleo. The pNesX is a NES emulator for the PlayStation that I have created 16 years ago!

Emulation part was almost without change, the sound part was newly added.

Parts

STM32 Nucleo F446RE
QVGA 2.2 TFT SPI (with the SD card slot)
Audio jack(TS or TRS)
USB Connector
Register 100k, 10k, 4.7k, 100
Capacitor 0.01uF, 2.2uF
Breadboard
Wires
Computer Speakers
USB GamePad

Wiring diagram

/media/uploads/beaglescout007/nucleo_ex06_emu.png

TFT J2Nucleo
VCC3V3
GNDGND
CSPB_5(D4)
ResetPA_10(D2) Pull Up(100k)
D/CPA_8(D7)
MOSIPA_7(D11)
SCKPA_5(D13)
LEDLED-100ohm-3V3
MISOPA_6(D12)
TFT J4Nucleo
SD_CSPA_9
SD_MOSIPB_15
SD_MISOPB_14
SD_SCKPB_13
AudioNucleo
TIPPA_4(A2)
USB con.Nucleo
GNDGND
+PA_12
-PA_11
5V5V

https://youtu.be/jL24IjT6LnI

Limitations

  • Since the rest of the RAM is about 50kbyte, maximum capacity of the game ROM is about 50kbyte.
  • The length of the file name up to 32 characters.
  • The number of files in the folder is up to 100.

Used Library

Committer:
beaglescout007
Date:
Sun Apr 03 07:45:29 2016 +0000
Revision:
0:3dac1f1bc9e0
Release

Who changed what in which revision?

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