Daily Archives: 2019-01-04

Tutorial: VoCore2+Screen Port Super Marie Bros.

The screen is ready and works pretty well, I am having a lot of fun 🙂

I am trying to port two version of NES simulators, one is LiteNES, another one is LaiNES. LiteNES is working pretty smooth but it has many bugs, some codes are broken; LaiNES is good and less bugs, but it is very very very slow, only 1/6 speed of LiteNES. I do not have much time to fix the bugs or optimize code. I guess it is a pretty funny process to fix it.

Here I explain how I port the two NES. Please download latest SDK of the screen(vocore.io/screen.html), in demo folder, we have a firmware with frame buffer driver, which is much easier for you port applications, or you can use the fbusb.ko driver to make your own.

fbusb.ko depends on framebuffer driver, usb driver and some sys_* draw function of framebuffer, please make sure every function is implied in kernel to make sure it works normal.

LiteNES requires to port keyboard and pixel display function.

To use framebuffer, here is my sample code.

void nes_hal_init()
{
	...

	// map framebuffer to local, so we can access it directly.
	int fd = open("/dev/fb0", O_RDWR);
	if (fd <= 0) {
		printf("frame buffer is not exist, exit.\n");
		exit(-1);
	}

	framebuffer = mmap(NULL, FBMAP_SIZE, PROT_WRITE, MAP_SHARED, fd, 0);
	if (framebuffer == NULL) {
		printf("can not map to frame buffer, exit.\n");
		exit(-1);
	}

	...

}

...

void nes_flip_display()
{
	if (framecount++ % 2)
		return;

	// directly write to middle of the frame buffer.
	memcpy(framebuffer + 144 * 480, local, LOCAL_SIZE);
}

I use a thread to handle the keyboard input…Maybe async is another better way, but its code might complex, so I make it easy.

Thread will update a key table, so app can directly read from the key table to get keys’ states.

void* keyboard_thread(void *arg)
{
	struct input_event ie;
	int kf;

	kf = open("/dev/input/event0", O_RDONLY);
	if (kf < 0) {
		printf("keyboard is not exist, input ignore.\n");
		return NULL;
	}

	while (1) {
		int size;
		size = read(kf, &ie, sizeof(struct input_event));
		if (size != sizeof(struct input_event))
			break;

		if (ie.type != EV_KEY || ie.code >= MAX_KEYCODE)
			continue;

		key_table[ie.code] = ie.value;
		if (ie.code == KEY_ESC)
			break;
	};

	close(kf);
	return arg;
}

PS: LiteNES is great but just bugs are weird, it has memory leak, no idea where it is but it write to the framebuffer area do not belong to it, should be the ppu engine issue.

PSS: source code here http://vonger.cn/misc/screen/LaiNES.tar.xz, http://vonger.cn/misc/screen/LiteNES.tar.xz