As being said in the log title. I had been doing this in an on-and-off manner since 2015 - I started this out using a STM32F4 discovery board with some screen on it and 8MB SDRAM. The code was obtained from the OpenEDV forums - with my limited Mandarin, I had to constantly use the Google translate so I won't get lost in that ocean! It worked... but there's no sound, and with all kinds of troubles I went through in life, I shelved that for like two years without working on this one.
It may seem as a lame excuse, and I admit - NES emulation is not something I can learn in a mere few weeks . Despite being such an old (and mostly being copied by Chinese factories for cheap knockoffs) architecture, it is still being a very popular console for everyone. I used to have a "Micro Genius" when I was a kid and spent some weekends playing those games.
Back to the main story - I have taken that code again and try to see if any of the PIC32MZs could fit on it. It did - and I have used the beaglescout007's emulator code to start with. It worked - but some games were not emulated properly. I will have to put this first try on the Github someday!
Then, curiously, I found that same emulator I took in 2015 and see if it also fit into that microcontroller. There are some major challenges there - especially the serial TFT and the sound generation mechanism.
Let me point out some important matters regarding to the porting:
1.) nes_main.cpp
- inline void draw_frame(void) : Pushing the pixels line-by-line doesn't work in this emulation. I don't know why, and I'm pretty sure it has a lot to do with the slower SPI interface, as the original states that it is using a parallel TFT. I had to reserve 256x240x2 bytes (the 2 at the end is because for 16-bit color) for the frame buffer and then let the PPU emulator draw this in the memory line-by-line. This function sets up the DMA and then start streaming the pixels right away once the V-sync is done.
2.) APU.cpp
- The nearest and the best one is by beaglescout007's APU emulator code. Some of the author's sound implementation in the code give me some clues on how I could slot in the thing without causing a lot of disasters in the emulation.
- It looks like whatever things done in the APU is being triggered by the PPU's scanline, so if there are any sound generation being done, it must be triggered at the certain scanline number:
nes_main.cpp, NesFrameCycle():
//Added APU routines:
switch (PPU_scanline) {
case SCAN_APU_CLK1: // 240Hz
case SCAN_APU_CLK3: // 240Hz
pNesX_ApuClk_240Hz();
break;
case SCAN_APU_CLK2: // 240Hz 120Hz
pNesX_ApuClk_240Hz();
pNesX_ApuClk_120Hz();
break;
case SCAN_APU_CLK4: // 240Hz 120Hz 60Hz
pNesX_ApuClk_240Hz();
pNesX_ApuClk_120Hz();
pNesX_ApuClk_60Hz();
break;
default: break;
}
I believe that I could put the same code into other emulators - and this is the first one I have tried so far.
- void ApuInit() : You need to start and initialize the timer and it's interrupts for the sound generation. Set up the PWM frequency for 24kHz. And of course, since different microcontrollers have different interrupt vectors and function, you need to place the body of the code in the void __USER_ISR timer2isr(void) into there.
3.) Joypad.cpp:
- I've used an NES mini classic controller which uses I2C protocol instead of the classic one with the shift register.
- NES_JoyPadReset(void) : The function captures the entire button states first and dump it into the 8-bit data form for the 6502 processor to be read.
- NES_GetJoyPadVlaue(unsigned char JOYPAD_INPUT) : This function then takes the first bit out (the first button being A) and shift to the right once, and it wraps back afterwards. For reference, you can read there: http://blog.tozt.net/2014/10/15/writing-an-nes-game-part-3/
So that concludes the log for today. There are some other issues like the sounds still being nasty and the emulator doesn't work as it should for some games, and hopefully some NES experts can share us some cool ideas here!
Discussions
Become a Hackaday.io Member
Create an account to leave a comment. Already have an account? Log In.