Skip to content →

implementing controls

Now we are at a stage, where we can implement controls, to see if the first games on the NROM mapper really are running properly, or if there are still bugs left.

For now, we will be okay with implementing the first controller. To do that, we will intercept writes and reads to 0x4016 (controller data for the second controller is read from 0x4017). A write to 0x4016 enables or disables polling for the inputs (1=enable, 0=disable). Once the polling is enabled, there will be reads from 0x4016, one bit at a time, for each button / direction. The reading order is as follows:

0 - A 
1 - B 
2 - Select 
3 - Start 
4 - Up 
5 - Down 
6 - Left 
7 - Right 

Inside my function, where I handle the window events, I pass the keyboard map to my input functions, to check which buttons are pressed.

uint8_t* keys = (uint8_t*)SDL_GetKeyboardState(NULL);
//	pass inputs
setController1(keys);
void setController1(uint8_t *SDL_keys) {
	resetController1();
	if (SDL_keys[SDL_SCANCODE_J])
		a1 = 1;
	if (SDL_keys[SDL_SCANCODE_K])
		b1 = 1;
	if (SDL_keys[SDL_SCANCODE_S])
		down1 = 1;
	if (SDL_keys[SDL_SCANCODE_A])
		left1 = 1;
	if (SDL_keys[SDL_SCANCODE_D])
		right1 = 1;
	if (SDL_keys[SDL_SCANCODE_W])
		up1 = 1;
	if (SDL_keys[SDL_SCANCODE_Q])
		select1 = 1;
	if (SDL_keys[SDL_SCANCODE_E])
		start1 = 1;
}

uint8_t readController1(uint8_t bit) {
	switch (bit) {
	case 0:
		return a1;
		break;
	case 1:
		return b1;
		break;
	case 2:
		return select1;
		break;
	case 3:
		return start1;
		break;
	case 4:
		return up1;
		break;
	case 5:
		return down1;
		break;
	case 6:
		return left1;
		break;
	case 7:
		return right1;
		break;
	default:
		return 0;
		break;
	}
}

Now, we can read out the actual bits on reads of 0x4016.

case 0x4016:		//	CONTROLLER #1
	if (poll_input >= 0) {
		uint8_t ret = readController1(poll_input++);
		if (poll_input > 7)
			poll_input = -1;	//	disable polling
		return ret | 0x40;
	}
	return 0x40;
	break;

Comments

Leave a Reply