NESe (pronounced "Nessie") is a NES emulator based on the e6502 emulator, also written in C with a focus on speed and portability for use on embedded platforms, especially ARM.
Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

114 rindas
3.2KB

  1. #include <stdio.h>
  2. #include "nes.h"
  3. #include "mapper.h"
  4. uint8_t nes_mem_read(nes* sys, uint16_t addr) {
  5. uint8_t val = 0;
  6. if (addr < nes_mem_ppu_start) {
  7. addr = (addr - nes_mem_ram_start) & (nes_mem_ram_size - 1);
  8. val = sys->ram[addr];
  9. } else if (addr < nes_mem_apu_start) {
  10. addr = (addr - nes_mem_ppu_start) & (nes_ppu_map_size - 1);
  11. val = nes_ppu_read(&sys->ppu, nes_mem_ppu_start + addr);
  12. } else if ( nes_input_1_reg == addr ||
  13. nes_input_2_reg == addr) {
  14. val = nes_input_read(&sys->input, addr);
  15. } else if (addr < nes_mem_exp_start) {
  16. val = nes_apu_read(&sys->apu, addr);
  17. } else {
  18. val = nes_map_read(sys->cart.mapper, addr);
  19. }
  20. return val;
  21. }
  22. void nes_mem_write(nes* sys, uint16_t addr, uint8_t val) {
  23. if (addr < nes_mem_ppu_start) {
  24. addr = (addr - nes_mem_ram_start) & (nes_mem_ram_size - 1);
  25. sys->ram[addr] = val;
  26. } else if (addr < nes_mem_apu_start) {
  27. addr = (addr - nes_mem_ppu_start) & (nes_ppu_map_size - 1);
  28. nes_ppu_write(&sys->ppu, nes_mem_ppu_start + addr, val);
  29. } else if (nes_ppu_dma_reg == addr) {
  30. OAM_LOG("PPU: OAM DMA $%02x00 > $%02x\n", val, sys->ppu.oam_addr);
  31. uint8_t* buf = (uint8_t*)sys->ppu.oam;
  32. for (int i = 0; i < nes_ppu_oam_size; ++i) {
  33. buf[(uint8_t)(i + sys->ppu.oam_addr)] =
  34. nes_mem_read(sys, ((uint16_t)val << 8) + i);
  35. }
  36. sys->cpu.cycle += 513U;
  37. // Other subsystem cycles are driven by CPU cycles
  38. } else if (addr == nes_input_set_reg) {
  39. nes_input_write(&sys->input, addr, val);
  40. } else if (addr < nes_mem_exp_start) {
  41. nes_apu_write(&sys->apu, addr, val);
  42. } else {
  43. nes_map_write(sys->cart.mapper, addr, val);
  44. }
  45. }
  46. static void nes_irq(void* sys, int active) {
  47. e6502_set_irq(&((nes*)sys)->cpu, active);
  48. }
  49. int nes_init(nes* sys, int audio_freq) {
  50. e6502_init(&sys->cpu, (e6502_Read*)nes_mem_read,
  51. (e6502_Write*)nes_mem_write, sys);
  52. nes_map_set_irq(sys->cart.mapper, nes_irq, sys);
  53. nes_ppu_init(&sys->ppu, &sys->cart);
  54. return nes_apu_init(
  55. &sys->apu,
  56. nes_clock_master_num / nes_clock_master_den,
  57. audio_freq,
  58. (uint8_t(*)(void*, uint16_t))nes_mem_read,
  59. sys
  60. );
  61. }
  62. void nes_reset(nes* sys) {
  63. e6502_reset(&sys->cpu);
  64. nes_ppu_reset(&sys->ppu);
  65. nes_apu_reset(&sys->apu);
  66. }
  67. nes_ppu_Result nes_step(nes* sys, int* run) {
  68. nes_ppu_Result result = ppu_Result_Halt;
  69. int cpu_run = e6502_step(&sys->cpu);
  70. if (cpu_run > 0) {
  71. int master_cycles = cpu_run * nes_clock_cpu_div;
  72. nes_apu_Result aresult = nes_apu_run(&sys->apu,
  73. master_cycles);
  74. // TODO: Does this conflict with MMC3?
  75. e6502_set_irq(&sys->cpu, aresult == apu_Result_IRQ);
  76. int ppu_cycles = master_cycles / nes_clock_ppu_div;
  77. result = nes_ppu_run(&sys->ppu, ppu_cycles);
  78. if (result == ppu_Result_VBlank_On) {
  79. e6502_set_nmi(&sys->cpu, 1);
  80. } else if (result == ppu_Result_VBlank_Off) {
  81. e6502_set_nmi(&sys->cpu, 0);
  82. }
  83. if (run) *run = master_cycles;
  84. }
  85. return result;
  86. }