SNES Emulator (very early test)

Post Reply
ducalex
Posts: 32
Joined: Sun May 19, 2019 3:29 am
languages_spoken: english
Has thanked: 9 times
Been thanked: 24 times
Contact:

SNES Emulator (very early test)

Unread post by ducalex » Sun May 26, 2019 9:24 am

Hello!

I've ported snes9x to the Odroid GO. Although I consider this very cool, it is very very early in development and it is not currently playable and might never be.

The ESP32 is, on paper, capable of running SNES at full speed. However snes9x is written to be portable rather than ultra efficient on each specific architectures, which limits the amount of optimization that can be done short of rewriting it. In other words my experiment will probably never run perfectly but I will push it as far as my skills allow me to!



Previous test: https://www.youtube.com/watch?v=eMd9S6ZRh4A

Couple images: https://imgur.com/a/3xQHGuI

Instructions:
Put snes9x.fw in /sdcard/odroid/firmware and put your roms in /sdcard/odroid/roms/snes/.

Caveats:
- ROMS bigger than 2MB won't work, there isn't enough RAM
- It is running very slow
- No sound
- No saves
- No accelerator chips supported

Button mapping:

Code: Select all

SNES     Odroid
A             A
B             B
X           START
Y           SELECT
START   VOLUME
SELECT  MENU
L           None
R          None

Source code
https://github.com/ducalex/snes9x-esp32

Downloads
Attachments
snes9x.zip
Third test build (newest)
Enabled g++ optimization, gained another 5%
(488.62 KiB) Downloaded 40 times
Last edited by ducalex on Thu May 30, 2019 11:44 am, edited 4 times in total.
These users thanked the author ducalex for the post (total 3):
mad_ady (Sun May 26, 2019 2:05 pm) • ripper121 (Sun May 26, 2019 3:49 pm) • odroid (Tue May 28, 2019 10:01 am)

lordhardware
Posts: 78
Joined: Sat Sep 20, 2014 11:56 pm
languages_spoken: english
ODROIDs: U3
Odroid-W
Has thanked: 3 times
Been thanked: 5 times
Contact:

Re: SNES Emulator (very early test)

Unread post by lordhardware » Mon May 27, 2019 2:20 pm

Odd that there's still no replies.

I'll check this out tonight, from what I remember from early emu days, Uniraces was a pretty low req. SNES game so maybe benchmark with that?

pmprog
Posts: 54
Joined: Thu Oct 18, 2018 4:01 am
languages_spoken: english
ODROIDs: ODROID-GO
Has thanked: 4 times
Been thanked: 1 time
Contact:

Re: SNES Emulator (very early test)

Unread post by pmprog » Mon May 27, 2019 2:38 pm

I must admit, looks impressive...

I seem to be struggling to get more than 15fps doing very little, never mind emulating anything

User avatar
odroid
Site Admin
Posts: 31404
Joined: Fri Feb 22, 2013 11:14 pm
languages_spoken: English
ODROIDs: ODROID
Has thanked: 55 times
Been thanked: 187 times
Contact:

Re: SNES Emulator (very early test)

Unread post by odroid » Tue May 28, 2019 10:01 am

Very interesting :o
I couldn't expect a running SNES on the GO even it looks quite slow at this moment.

ducalex
Posts: 32
Joined: Sun May 19, 2019 3:29 am
languages_spoken: english
Has thanked: 9 times
Been thanked: 24 times
Contact:

Re: SNES Emulator (very early test)

Unread post by ducalex » Tue May 28, 2019 11:46 am

I've made some modifications, it is running a bit faster! Still not playable unfortunately. Video has been updated as well as the zip.
Super Mario World is currently running 3.5x too slow and in the previous build it was about 5x.
lordhardware wrote:
Mon May 27, 2019 2:20 pm
I'll check this out tonight, from what I remember from early emu days, Uniraces was a pretty low req. SNES game so maybe benchmark with that?
Uniracers doesn't seem to run but I didn't investigate why yet. The game starts but eventually black screen.

Edit: Uniracers DO run now, but as slow as you can imagine :)
Last edited by ducalex on Sat Jun 15, 2019 2:09 am, edited 1 time in total.

ducalex
Posts: 32
Joined: Sun May 19, 2019 3:29 am
languages_spoken: english
Has thanked: 9 times
Been thanked: 24 times
Contact:

Re: SNES Emulator (very early test)

Unread post by ducalex » Sat Jun 15, 2019 2:08 am

Hello!

This is a quick update to let you know that I will stop working on this project. The biggest reason is that I cannot figure out how to profile function calls on the esp32 (or if it is indeed possible). The snes9x execution flow is pretty complicated so manually adding tracking code proved to be futile.

If anyone is willing to teach me how to profile function calls on the esp32 I'd be very happy to have a second look.


But for the record, and if someome wants to pick up where I left it, here's a list of things I've tried or considered so far:
  • Modify the emulation timings. I managed about 5% speed gain before the games were too badly glitchy. It's not an ideal route to break games so I dismissed it.
  • Use both cpu cores. I moved some of the PPU rendering logic to the second score. While it does provide good performance, it is incredibly glitchy if not synchronized. Once synchronized the performance gain was a lot more modest, 10% perhaps. I'm sure this is an avenue worth exploring again in the future. Sound can also be in its own thread, when implemented. But the rest of the emulator cannot be broken down further.
  • Reassess the types used everywhere. I've gained a few percents by using smaller types where possible, but the code is large and it takes time to test nothing breaks. Some structures benefited from being realigned as well.
  • Dynamic recompiler. I have not tried it, but the ESP32 is indeed able to load code in RAM and execute it.
  • Move key ram blocks to internal RAM instead of SPIRAM. I've gained a few percent. I was hoping for more of a difference but apparently SPIRAM and Internal ram are similar in speed..? Further experimentation on which blocks of RAM is been put in internal RAM could be needed.
These users thanked the author ducalex for the post:
Melon Bread (Sat Jun 15, 2019 11:59 am)

pmprog
Posts: 54
Joined: Thu Oct 18, 2018 4:01 am
languages_spoken: english
ODROIDs: ODROID-GO
Has thanked: 4 times
Been thanked: 1 time
Contact:

Re: SNES Emulator (very early test)

Unread post by pmprog » Tue Jun 18, 2019 2:11 pm

I downloaded Neil Kolban's Book on ESP32. I haven't read much of it, because my time with the ESP32 and go have been rather limited, but there's a section on debugging, and it sounds like there's no profiling type tools available, just output logging.
Even though i haven't read much of it, I'd probably recommend it, as what little i have read seems very thorough.

I'm impressed you got add far as you did though

fileoffset
Posts: 1
Joined: Mon Jul 22, 2019 7:18 pm
languages_spoken: english
ODROIDs: go,xu2,c2
Has thanked: 0
Been thanked: 0
Contact:

Re: SNES Emulator (very early test)

Unread post by fileoffset » Mon Jul 22, 2019 7:23 pm

I used this admittedly low-tech method when I was testing some performance improvements to the NES emu:

Code: Select all

int cycles = xthal_get_ccount();

function_to_test();

int now_cycles = xthal_get_ccount();
printf("Frame took: %d\n", now_cycles - cycles);

ducalex
Posts: 32
Joined: Sun May 19, 2019 3:29 am
languages_spoken: english
Has thanked: 9 times
Been thanked: 24 times
Contact:

Re: SNES Emulator (very early test)

Unread post by ducalex » Mon Jul 22, 2019 11:34 pm

fileoffset wrote:
Mon Jul 22, 2019 7:23 pm
I used this admittedly low-tech method when I was testing some performance improvements to the NES emu:

Code: Select all

int cycles = xthal_get_ccount();

function_to_test();

int now_cycles = xthal_get_ccount();
printf("Frame took: %d\n", now_cycles - cycles);
That is good advice. I used a similar method with esp_timer_get_time(). The problem was that the SNES codebase is fairly large and what I need is the total time spent in each function (the sum of all its calls) and tracking them one by one is a total pain.

I've been experimenting with gcc's -finstrument-functions recently and the results are promising. Here's what I wrote so far:

Code: Select all

typedef struct {
	void *address;
	uint call_stack;
	uint calls_count;
	uint total_time;
	uint start_time;
} func_entry_t;

func_entry_t functions[2048];
const ushort functions_count = 2048;

extern "C" __attribute__((no_instrument_function))
IRAM_ATTR void __cyg_profile_func_enter(void *this_fn, void *call_site)
{
	for (ushort i = 0; i < functions_count; i++) {
		if (functions[i].address == 0) { 
			functions[i].address = this_fn;
		}
		
		if (functions[i].address == this_fn) {
			functions[i].start_time = esp_timer_get_time();
			functions[i].call_stack++;
			break;
		}
	}
}

extern "C" __attribute__((no_instrument_function))
IRAM_ATTR void __cyg_profile_func_exit(void *this_fn, void *call_site)
{
	for (ushort i = 0; i < functions_count; i++) {
		if (functions[i].address == this_fn) {
			functions[i].calls_count++;
			functions[i].call_stack--;
			functions[i].total_time += esp_timer_get_time() - functions[i].start_time;
			break;
		}
	}
}

void dump_function_stats_task(void *arg)
{
	while (1) {
		printf("Function stats:\n");
		for (uint i = 0; i < functions_count; i++) {
			if (functions[i].address == 0) break;
			func_entry_t *function = &functions[i];
			printf("0x%x: Calls: %d Total time: %.3f\n", 
				(int)function->address, function->calls_count, (float)function->total_time / 1000000);
		}
		vTaskDelay(6000);
	}
}

It doesn't handle nested calls and stacks and it is probably slower than it could be. In fact the emulator with the tracing functions doing NOP runs about 50x slower. Which is fully acceptable, but when I add my code it jumps to 1000x slower, it takes 15 minutes to reach title screen in SMW :(. But it "works"!

Here's an example output taken at the nintendo logo screen in super mario world:
Image
Raw log: https://gist.github.com/ducalex/40bbdb5 ... 53a866fe43

Post Reply

Return to “Game Emulators”

Who is online

Users browsing this forum: No registered users and 1 guest