Io.cpp
上传用户:luhy168
上传日期:2022-01-10
资源大小:240k
文件大小:9k
源码类别:

模拟服务器

开发平台:

Visual C++

  1. //------------------------------------------------------------------------------
  2. // Name: Io.cpp
  3. // Desc: Holds all the functions to read and write to memory.
  4. //------------------------------------------------------------------------------
  5. // Includes
  6. #include <windows.h>
  7. #include "Io.h"
  8. #include "Sound.h"
  9. //------------------------------------------------------------------------------
  10. // Name: GetMemoryByte()
  11. // Desc: Returns a byte from the Cpu's memory.
  12. //------------------------------------------------------------------------------
  13. BYTE __stdcall GetMemoryByte(WORD wAddress)
  14. {
  15. if (wAddress >= 0x8000 && wAddress < 0xC000)
  16. return CPU.pbyPRGROMBank1[wAddress-0x8000];
  17. else if (wAddress >= 0xC000 && wAddress <= 0xFFFF)
  18. return CPU.pbyPRGROMBank2[wAddress-0xC000];
  19. else
  20. return CPU.Memory[wAddress];
  21. } // end GetMemoryByte()
  22. //------------------------------------------------------------------------------
  23. // Name: GetMemoryPointer()
  24. // Desc: Returns a pointer to a byte from the Cpu's memory.
  25. //------------------------------------------------------------------------------
  26. BYTE* __stdcall GetMemoryPointer(WORD wAddress)
  27. {
  28. if (wAddress >= 0x8000 && wAddress < 0xC000)
  29. return (&(CPU.pbyPRGROMBank1[wAddress-0x8000]));
  30. else if (wAddress >= 0xC000 && wAddress <= 0xFFFF)
  31. return (&(CPU.pbyPRGROMBank2[wAddress-0xC000]));
  32. else
  33. return (&(CPU.Memory[wAddress]));
  34. } // end GetMemoryPointer()
  35. //------------------------------------------------------------------------------
  36. // Name: ReadMemory()
  37. // Desc: N/A
  38. //------------------------------------------------------------------------------
  39. BYTE __stdcall ReadMemory(WORD wAddress)
  40. {
  41. static BYTE byVRAMBuffer; // See the case where wAddress=0x2007.
  42. if (wAddress >= 0x8000 && wAddress <= 0xFFFF)
  43. return MapperOnRead(wAddress);
  44. else
  45. {
  46. // Check for all the register reads.
  47. if (wAddress == 0x2002)
  48. {
  49. BYTE byRetVal = CPU.Memory[0x2002];
  50. // Clear the vblank bit.
  51. CPU.Memory[0x2002] &= 0x7F;
  52. // Clear the VRAM toggle.
  53. byVRAMAddrRegToggle = 0;
  54. return byRetVal;
  55. }
  56. else if (wAddress == 0x2003)
  57. {
  58. return CPU.Memory[0x2003];
  59. }
  60. else if (wAddress == 0x2004)
  61. {
  62. return abySPRRAM[CPU.Memory[0x2003]];
  63. }
  64. else if (wAddress == 0x2007)
  65. {
  66. /*
  67.  * Cut and paste from yoshi's document nestech.txt
  68.  *
  69.  O. PPU Quirks
  70.  -------------
  71. The first read from VRAM is invalid. Due to this aspect, the NES will
  72. returned pseudo-buffered values from VRAM rather than linear as expec-
  73. ted. See the below example:
  74. VRAM $2000 contains $AA $BB $CC $DD.
  75. VRAM incrementation value is 1.
  76. The result of execution is printed in the comment field. 
  77. LDA #$20
  78. STA $2006
  79. LDA #$00
  80. STA $2006        ; VRAM address now set at $2000
  81. LDA $2007        ; A=??     VRAM Buffer=$AA
  82. LDA $2007        ; A=$AA    VRAM Buffer=$BB
  83. LDA $2007        ; A=$BB    VRAM Buffer=$CC
  84. LDA #$20
  85. STA $2006
  86. LDA #$00
  87. STA $2006        ; VRAM address now set at $2000
  88. LDA $2007        ; A=$CC    VRAM Buffer=$AA
  89. LDA $2007        ; A=$AA    VRAM Buffer=$BB
  90. As shown, the PPU will post-increment it's internal address data after
  91. the first read is performed. This *ONLY APPLIES* to VRAM $0000-3EFF
  92. (e.g. Palette data and their respective mirrors do not suffer from
  93. this phenomenon).
  94. */
  95. if (wVRAMAddress >= 0 && wVRAMAddress < 0x3F00)
  96. {
  97. BYTE byReturnVal = byVRAMBuffer;
  98. // Read the byte into the VRAM buffer.
  99. byVRAMBuffer = PPUReadMemory(wVRAMAddress);
  100. // Increment the address by 1 or 32 depending on the
  101. // status of bit 2 of reg $2000.
  102. (CPU.Memory[0x2000] & 4) ? (wVRAMAddress += 32) : wVRAMAddress++;
  103. return byReturnVal;
  104. }
  105. else
  106. return PPUReadMemory(wVRAMAddress);
  107. }
  108. // All the APU registers.
  109. else if (wAddress == 0x4015)
  110. {
  111. return APU_Read(wAddress);
  112. }
  113. else if (wAddress == 0x4016)
  114. {
  115. return Joy1.read();
  116. }
  117. // If its not one of the registers, then just write the byte to memory.
  118. else
  119. return CPU.Memory[wAddress];
  120. }
  121. return 0;
  122. } // end ReadMemory()
  123. //------------------------------------------------------------------------------
  124. // Name: WriteMemory()
  125. // Desc: Writes to CPU memory and checks to see if its a register write as
  126. //       well. Then depending on if its a register write, it does the
  127. //       appropriate action.
  128. //------------------------------------------------------------------------------
  129. VOID __stdcall WriteMemory(WORD wAddress, BYTE byData)
  130. {
  131. // PRG-ROM writes.
  132. if (wAddress >= 0x8000 && wAddress <= 0xFFFF)
  133. MapperOnWrite(wAddress, byData);
  134. else 
  135. {
  136. // Check for all the register writes.
  137. if (wAddress == 0x2000)
  138. {
  139. CPU.Memory[0x2000] = byData;
  140. }
  141. else if (wAddress == 0x2001)
  142. {
  143. CPU.Memory[0x2001] = byData;
  144. }
  145. else if (wAddress == 0x2003)
  146. {
  147. // Save the address to access sprite ram with.
  148. CPU.Memory[0x2003] = byData;
  149. }
  150. else if (wAddress == 0x2004)
  151. {
  152. // Write the data into the sprite ram at the
  153. // addres specified in register $2003.
  154. abySPRRAM[CPU.Memory[0x2003]] = byData;
  155. }
  156. else if (wAddress == 0x2005)
  157. {
  158. // The second write is the vertical scroll, the
  159. // first write is the horizontal scroll.
  160. if (byVRAMAddrRegToggle)
  161. byVScroll[0] = byData;
  162. else
  163. byHScroll[0] = byData;
  164. // Toggle to indicate that we are on the second write.
  165. byVRAMAddrRegToggle ^= 1;
  166. }
  167. else if (wAddress == 0x2006)
  168. {
  169. if (byVRAMAddrRegToggle)
  170. // Write the lower byte into the VRAM address register.
  171. *((BYTE*)(&wVRAMAddress)) = byData;
  172. else
  173. // Write the upper byte into the VRAM address register.
  174. *(((BYTE*)(&wVRAMAddress))+1) = byData;
  175. // Toggle to indicate that we are on the second write.
  176. byVRAMAddrRegToggle ^= 1;
  177. }
  178. else if (wAddress == 0x2007)
  179. {
  180. // Write the byte to video memory.
  181. PPUWriteMemory(wVRAMAddress, byData);
  182. // Increment the address by 1 or 32 depending on the
  183. // status of bit 2 of reg $2000.
  184. (CPU.Memory[0x2000] & 4) ? (wVRAMAddress += 32) : wVRAMAddress++;
  185. }
  186. // All the APU registers.
  187. else if (wAddress == 0x4003 || wAddress == 0x4015)
  188. {
  189. CPU.Memory[wAddress] = byData;
  190. APU_Write(wAddress, byData);
  191. }
  192. else if (wAddress == 0x4014)
  193. {
  194. // Transfers 256 bytes of memory into SPR-RAM. The address
  195. // read from is $100*N, where N is the value written.
  196. memcpy(abySPRRAM, &CPU.Memory[0x100*byData], 256);
  197. CPU.Memory[0x4014] = byData;
  198. }
  199. else if (wAddress == 0x4016)
  200. {
  201. Joy1.write(byData);
  202. CPU.Memory[0x4016] = byData;
  203. }
  204. // If its not one of the registers, then just write the byte to memory.
  205. else
  206. CPU.Memory[wAddress] = byData;
  207. }
  208. } // end WriteMemory()
  209. //------------------------------------------------------------------------------
  210. // Name: PPUReadMemory()
  211. // Desc: N/A
  212. //------------------------------------------------------------------------------
  213. BYTE __stdcall PPUReadMemory(WORD wAddress)
  214. {
  215. // Pattern table read.
  216. if (wAddress < 0x1000)
  217. return *((PPU.apbyPatternTables[0])+(wAddress));
  218. else if (wAddress >= 0x1000 && wAddress < 0x2000)
  219. return *((PPU.apbyPatternTables[1])+(wAddress-0x1000));
  220. else if (wAddress >= 0x2000 && wAddress < 0x3000)
  221. {
  222. if (wAddress >= 0x2000 && wAddress < 0x2400)
  223. return *(PPU.apbyNameTables[0] + (wAddress - 0x2000));
  224. else if (wAddress >= 0x2400 && wAddress < 0x2800)
  225. return *(PPU.apbyNameTables[1] + (wAddress - 0x2400));
  226. else if (wAddress >= 0x2800 && wAddress < 0x2C00)
  227. return *(PPU.apbyNameTables[2] + (wAddress - 0x2800));
  228. else
  229. return *(PPU.apbyNameTables[3] + (wAddress - 0x2C00));
  230. }
  231. else if (wAddress >= 0x3F00 && wAddress < 0x3F20)
  232. return PPU.abyPalettes[wAddress-0x3F00];
  233. else
  234. return 0;
  235. } // end PPUReadMemory()
  236. //------------------------------------------------------------------------------
  237. // Name: PPUWriteMemory()
  238. // Desc: N/A
  239. //------------------------------------------------------------------------------
  240. VOID __stdcall PPUWriteMemory(WORD wAddress, BYTE byData)
  241. {
  242. // Pattern table write.
  243. if (wAddress < 0x1000)
  244. *((PPU.apbyPatternTables[0])+(wAddress)) = byData;
  245. else if (wAddress >= 0x1000 && wAddress < 0x2000)
  246. *((PPU.apbyPatternTables[1])+(wAddress-0x1000)) = byData;
  247. else if (wAddress >= 0x2000 && wAddress < 0x3000)
  248. {
  249. if (wAddress >= 0x2000 && wAddress < 0x2400)
  250. *(PPU.apbyNameTables[0] + (wAddress - 0x2000)) = byData;
  251. else if (wAddress >= 0x2400 && wAddress < 0x2800)
  252. *(PPU.apbyNameTables[1] + (wAddress - 0x2400)) = byData;
  253. else if (wAddress >= 0x2800 && wAddress < 0x2C00)
  254. *(PPU.apbyNameTables[2] + (wAddress - 0x2800)) = byData;
  255. else
  256. *(PPU.apbyNameTables[3] + (wAddress - 0x2C00)) = byData;
  257. }
  258. else if (wAddress >= 0x3F00 && wAddress < 0x3F20)
  259. PPU.abyPalettes[wAddress-0x3F00] = byData;
  260. } // end PPUWriteMemory()