Welcome to mirror list, hosted at ThFree Co, Russian Federation.

snes2nes.c - github.com/ClusterM/snes2nes.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 06df142591c8fbb7f47de6b95008154e874d8064 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
#include "defines.h"
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <avr/eeprom.h>
#include "bits.h"
#include "gamepad.h"

#define LED_ON unset_bit(PORTB, 2)
#define LED_OFF set_bit(PORTB, 2)

volatile uint8_t nes_button_data;
volatile uint8_t shift;
volatile uint8_t turbo_counter;

// Clock
ISR(INT0_vect)
{
	shift <<= 1;
	if (nes_button_data & shift)
		PORTD |= 1;
	else 
		PORTD &= ~1;
}

// Strobe
ISR(INT1_vect)
{
	shift = 1;
	if (nes_button_data & shift)
		PORTD |= 1;
	else 
		PORTD &= ~1;
}

uint16_t get_template_buttons()
{
	uint16_t snes_buttons;
	if ((snes_buttons&0x0FFF) != 0x0FFF)
	do
	{
		PORTB ^= (1<<2);
		_delay_ms(50);
		snes_buttons = get_snes_gamepad();
	} while ((snes_buttons&0x0FFF) != 0x0FFF);
	LED_OFF;
	_delay_ms(200);
	
	int hold_time = 0;
	do
	{
		PORTB ^= (1<<2);
		_delay_ms(50);
		snes_buttons = get_snes_gamepad();
		if ((snes_buttons&0x0FFF) != 0x0FFF) 
			hold_time++;
		else
			hold_time = 0;
	} while (hold_time < 30);
	LED_OFF;
	_delay_ms(500);
	return snes_buttons;
}

int main (void)
{
	set_bit(DDRD, 0); // Данные - на выход
	unset_bit2(DDRD, 2, 3); // clock, strobe - на ввод
	set_bit(DDRB, 2); // Светодиод на вывод	

	set_bit2(MCUCR, ISC11, ISC10); // Прерывание при растущем strobe
	set_bit2(MCUCR, ISC01, ISC00); // Прерывание при растущем  clock
	set_bit(GICR, INT0); set_bit(GICR, INT1); // Активируем их

	sei(); // Глобальная активация прерываний
	
	// Right, Left, Down, Up, Start, Select, B, A
	init_snes_gamepad();
	
	int lr_hold_time = 0;
	uint16_t l_template = 0x0FFF;
	uint16_t r_template = 0x0FFF;
	eeprom_read_block(&r_template, (void*)0, 2);
	eeprom_read_block(&l_template, (void*)2, 2);
	
	while(1)		
	{
		// R, L, X, A, Right, Left, Down, Up, Start, Select, Y, B
		uint16_t snes_buttons = get_snes_gamepad();
		if ((snes_buttons&0x0FFF) != 0x0FFF)
		{
			LED_ON;
		} else {
			LED_OFF;
		}
		
		if (((snes_buttons&0x0FFF) == 0x07FB) || ((snes_buttons&0x0FFF) == 0x0BFB)) // R + select or L + select
		{
			if (lr_hold_time++ == 200)
			{
				nes_button_data = 0xFF; // Unpress nes buttons
				uint16_t template_buttons = get_template_buttons();
				template_buttons |= (0b11<<10); // Exclude L&R
				if ((snes_buttons&0x0FFF) == 0x07FB)
				{
					r_template = template_buttons;
					eeprom_write_block(&r_template, (void*)0, 2);
				} else {
					l_template = template_buttons;
					eeprom_write_block(&l_template, (void*)2, 2);
				}
				snes_buttons = 0x0FFF;
			}
		} else lr_hold_time = 0;
		
		if (!(snes_buttons&(1<<11))) snes_buttons &= r_template;
		if (!(snes_buttons&(1<<10))) snes_buttons &= l_template;
		
		uint8_t tmp = snes_buttons & 0b11111100;
		tmp |= (snes_buttons>>8)&1; // A
		tmp |= (snes_buttons&1)<<1; // B
		if (!(snes_buttons&(1<<9)) && ((turbo_counter%8) <= 3)) tmp &= ~1; // X -> Turbo A
		if (!(snes_buttons&(1<<1)) && ((turbo_counter%8) <= 3)) tmp &= ~2; // Y -> Turbo B
		
		if (!(snes_buttons&(1<<7)) && !(snes_buttons&(1<<6))) tmp |= 1<<7; // No left+right!
		if (!(snes_buttons&(1<<5)) && !(snes_buttons&(1<<4))) tmp |= 1<<5; // No up+down!
		
		nes_button_data = tmp;
		_delay_ms(10);
		turbo_counter++;
	}
}