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

github.com/ClusterM/snes2nes.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexey 'Cluster' Avdyukhin <clusterrr@clusterrr.com>2015-11-06 08:36:40 +0300
committerAlexey 'Cluster' Avdyukhin <clusterrr@clusterrr.com>2015-11-06 08:36:40 +0300
commitf9222dc2fe7c1bd21af85da31db292048559feaf (patch)
tree6c3c6c8c8ecf3ce26bb09ab43299d28978cc560a
First commit
-rw-r--r--Makefile148
-rw-r--r--bits.h12
-rw-r--r--defines.h8
-rw-r--r--gamepad.c223
-rw-r--r--gamepad.h54
-rw-r--r--snes2nes.c140
-rw-r--r--snes2nes.hex60
-rw-r--r--snes2nes.lay6bin0 -> 32894 bytes
8 files changed, 645 insertions, 0 deletions
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..5f471db
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,148 @@
+PRG = snes2nes
+OBJ = snes2nes.o gamepad.o
+LFUSE = E4
+HFUSE = D9
+MCU_PROGRAMMER = m8
+PROGRAMMER_TYPE = avrisp2
+PROGRAMMER_PORT = usb
+
+#MCU_TARGET = at90s2313
+#MCU_TARGET = at90s2333
+#MCU_TARGET = at90s4414
+#MCU_TARGET = at90s4433
+#MCU_TARGET = at90s4434
+#MCU_TARGET = at90s8515
+#MCU_TARGET = at90s8535
+#MCU_TARGET = atmega128
+#MCU_TARGET = atmega1280
+#MCU_TARGET = atmega1281
+MCU_TARGET = atmega8
+#MCU_TARGET = atmega163
+#MCU_TARGET = atmega164p
+#MCU_TARGET = atmega165
+#MCU_TARGET = atmega165p
+#MCU_TARGET = atmega168
+#MCU_TARGET = atmega169
+#MCU_TARGET = atmega169p
+#MCU_TARGET = atmega32
+#MCU_TARGET = atmega324p
+#MCU_TARGET = atmega325
+#MCU_TARGET = atmega3250
+#MCU_TARGET = atmega329
+#MCU_TARGET = atmega3290
+#MCU_TARGET = atmega48
+#MCU_TARGET = atmega64
+#MCU_TARGET = atmega640
+#MCU_TARGET = atmega644
+#MCU_TARGET = atmega644p
+#MCU_TARGET = atmega645
+#MCU_TARGET = atmega6450
+#MCU_TARGET = atmega649
+#MCU_TARGET = atmega6490
+#MCU_TARGET = atmega8
+#MCU_TARGET = atmega8515
+#MCU_TARGET = atmega8535
+#MCU_TARGET = atmega88
+#MCU_TARGET = attiny2313
+#MCU_TARGET = attiny24
+#MCU_TARGET = attiny25
+#MCU_TARGET = attiny26
+#MCU_TARGET = attiny261
+#MCU_TARGET = attiny44
+#MCU_TARGET = attiny45
+#MCU_TARGET = attiny461
+#MCU_TARGET = attiny84
+#MCU_TARGET = attiny85
+#MCU_TARGET = attiny861
+OPTIMIZE = -O2
+
+DEFS =
+LIBS =
+
+# You should not have to change anything below here.
+
+CC = avr-gcc
+
+# Override is only needed by avr-lib build system.
+
+override CFLAGS = -g -Wall $(OPTIMIZE) -mmcu=$(MCU_TARGET) $(DEFS)
+override LDFLAGS = -Wl,-Map,$(PRG).map
+
+OBJCOPY = avr-objcopy
+OBJDUMP = avr-objdump
+
+all: $(PRG).elf lst text eeprom
+
+$(PRG).elf: $(OBJ)
+ $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS)
+
+# dependency:
+clean:
+ rm -rf *.o $(PRG).elf *.eps *.png *.pdf *.bak
+ rm -rf *.lst *.map $(EXTRA_CLEAN_FILES)
+
+lst: $(PRG).lst
+
+%.lst: %.elf
+ $(OBJDUMP) -h -S $< > $@
+
+# Rules for building the .text rom images
+
+text: hex bin srec
+
+hex: $(PRG).hex
+bin: $(PRG).bin
+srec: $(PRG).srec
+
+%.hex: %.elf
+ $(OBJCOPY) -j .text -j .data -O ihex $< $@
+
+%.srec: %.elf
+ $(OBJCOPY) -j .text -j .data -O srec $< $@
+
+%.bin: %.elf
+ $(OBJCOPY) -j .text -j .data -O binary $< $@
+
+# Rules for building the .eeprom rom images
+
+eeprom: ehex ebin esrec
+
+ehex: $(PRG)_eeprom.hex
+ebin: $(PRG)_eeprom.bin
+esrec: $(PRG)_eeprom.srec
+
+%_eeprom.hex: %.elf
+ $(OBJCOPY) -j .eeprom --change-section-lma .eeprom=0 -O ihex $< $@ \
+ || { echo empty $@ not generated; exit 0; }
+
+%_eeprom.srec: %.elf
+ $(OBJCOPY) -j .eeprom --change-section-lma .eeprom=0 -O srec $< $@ \
+ || { echo empty $@ not generated; exit 0; }
+
+%_eeprom.bin: %.elf
+ $(OBJCOPY) -j .eeprom --change-section-lma .eeprom=0 -O binary $< $@ \
+ || { echo empty $@ not generated; exit 0; }
+
+# Every thing below here is used by avr-libc's build system and can be ignored
+# by the casual user.
+
+FIG2DEV = fig2dev
+EXTRA_CLEAN_FILES = *.hex *.bin *.srec
+
+dox: eps png pdf
+
+eps: $(PRG).eps
+png: $(PRG).png
+pdf: $(PRG).pdf
+
+%.eps: %.fig
+ $(FIG2DEV) -L eps $< $@
+
+%.pdf: %.fig
+ $(FIG2DEV) -L pdf $< $@
+
+%.png: %.fig
+ $(FIG2DEV) -L png $< $@
+
+program: hex
+ avrdude -V -p $(MCU_PROGRAMMER) -c $(PROGRAMMER_TYPE) -P $(PROGRAMMER_PORT) -U flash:w:$(PRG).hex -U lfuse:w:0x$(LFUSE):m -U hfuse:w:0x$(HFUSE):m
diff --git a/bits.h b/bits.h
new file mode 100644
index 0000000..737199f
--- /dev/null
+++ b/bits.h
@@ -0,0 +1,12 @@
+#define set(reg,value) reg |= (value)
+#define unset(reg,value) reg &= ~(value)
+#define set_bit(reg,value) reg |= (_BV(value))
+#define set_bit2(reg,value1,value2) reg |= (_BV(value1) | _BV(value2))
+#define set_bit3(reg,value1,value2,value3) reg |= (_BV(value1) | _BV(value2) | _BV(value3))
+#define set_bit4(reg,value1,value2,value3,value4) reg |= (_BV(value1) | _BV(value2) | _BV(value3) | _BV(value4))
+#define set_bit5(reg,value1,value2,value3,value4,value5) reg |= (_BV(value1) | _BV(value2) | _BV(value3) | _BV(value4) | _BV(value5))
+#define unset_bit(reg,value) reg &= ~(_BV(value))
+#define unset_bit2(reg,value1,value2) reg &= ~(_BV(value1) | _BV(value2))
+#define unset_bit3(reg,value1,value2,value3) reg &= ~(_BV(value1) | _BV(value2) | _BV(value3))
+#define unset_bit4(reg,value1,value2,value3,value4) reg &= ~(_BV(value1) | _BV(value2) | _BV(value3) | _BV(value4))
+#define unset_bit5(reg,value1,value2,value3,value4,value5) reg &= ~(_BV(value1) | _BV(value2) | _BV(value3) | _BV(value4) | _BV(value5))
diff --git a/defines.h b/defines.h
new file mode 100644
index 0000000..6d28096
--- /dev/null
+++ b/defines.h
@@ -0,0 +1,8 @@
+#define F_CPU 8000000L
+
+#define SNES_ENABLED
+#define SNES_PORT B
+#define SNES_LATCH_PIN 3
+#define SNES_CLOCK_PIN 4
+#define SNES_DATA_PIN 5
+
diff --git a/gamepad.c b/gamepad.c
new file mode 100644
index 0000000..0494208
--- /dev/null
+++ b/gamepad.c
@@ -0,0 +1,223 @@
+#include "defines.h"
+#include <avr/io.h>
+#include <util/delay.h>
+#include "gamepad.h"
+
+#ifdef NES_ENABLED
+
+void init_nes_gamepad()
+{
+ NES_PORT_DDR |= 1<<NES_LATCH_PIN; // Latch, output
+ NES_PORT_DDR |= 1<<NES_CLOCK_PIN; // Clock, output
+ NES_PORT_DDR &= ~(1<<NES_DATA_PIN); // Data, input
+ NES_PORT_PORT |= 1<<NES_DATA_PIN; // Data, pull-up
+}
+
+uint8_t get_nes_gamepad()
+{
+ uint8_t gamepad_data = 0;
+ NES_PORT_PORT &= ~(1<<NES_LATCH_PIN); // Latch
+ int b;
+ for (b = 0; b < 8; b++)
+ {
+ NES_PORT_PORT &= ~(1<<NES_CLOCK_PIN); // Clock
+ _delay_us(10);
+ gamepad_data |= (((NES_PORT_PIN>>NES_DATA_PIN)&1)<<b);
+ NES_PORT_PORT |= 1<<NES_CLOCK_PIN; // Clock
+ _delay_us(10);
+ }
+ NES_PORT_PORT |= 1<<NES_LATCH_PIN; // Latch
+ return gamepad_data;
+}
+#endif
+
+#ifdef SNES_ENABLED
+void init_snes_gamepad()
+{
+ SNES_PORT_DDR |= 1<<SNES_LATCH_PIN; // Latch, output
+ SNES_PORT_DDR |= 1<<SNES_CLOCK_PIN; // Clock, output
+ SNES_PORT_DDR &= ~(1<<SNES_DATA_PIN); // Data, input
+ SNES_PORT_PORT |= 1<<SNES_DATA_PIN; // Data, pull-up
+}
+
+uint16_t get_snes_gamepad()
+{
+ uint16_t gamepad_data = 0;
+ SNES_PORT_PORT &= ~(1<<SNES_LATCH_PIN); // Latch
+ int b;
+ for (b = 0; b < 16; b++)
+ {
+ SNES_PORT_PORT &= ~(1<<SNES_CLOCK_PIN); // Clock
+ _delay_us(10);
+ gamepad_data |= ((uint16_t)((SNES_PORT_PIN>>SNES_DATA_PIN)&1)<<b);
+ SNES_PORT_PORT |= 1<<SNES_CLOCK_PIN; // Clock
+ _delay_us(10);
+ }
+ SNES_PORT_PORT |= 1<<SNES_LATCH_PIN; // Latch
+ return gamepad_data;
+}
+#endif
+
+#ifdef N64_ENABLED
+void init_n64_gamepad()
+{
+ TCCR0 |= _BV(CS00); // Timer
+ N64_PORT_DDR &= ~(1<<N64_DATA_PIN); // Input
+ N64_PORT_PORT &= ~(1<<N64_DATA_PIN); // No pull-up (using external resistor)
+}
+
+int get_n64_gamepad(uint8_t* data)
+{
+ int b, bit;
+ N64SEND_0; N64SEND_0; N64SEND_0; N64SEND_0; N64SEND_0; N64SEND_0; N64SEND_0; N64SEND_1; N64SEND_STOP;
+ for (b = 0; b < 4; b++)
+ {
+ data[b] = 0;
+ for (bit = 0; bit < 8; bit++)
+ {
+ TCNT0 = 0;
+ while (!N64SIGNAL) if (TCNT0 >= 0xF0) return 0;
+ TCNT0 = 0;
+ while(N64SIGNAL) if (TCNT0 >= 0xF0) return 0;
+ data[b] = data[b]<<1;
+ if (TCNT0 < 0x24 * F_CPU / 20000000UL) data[b] |= 1;
+ }
+ }
+ return 1;
+}
+#endif
+
+#ifdef SMD_ENABLED
+void init_smd_gamepad()
+{
+ SMD_SELECT_PORT_DDR |= 1<<SMD_SELECT_PIN; // Select, output
+ SMD_DATA_PORT_DDR &= ~(1<<SMD_DATA0_PIN); // Data 0, input
+ SMD_DATA_PORT_DDR &= ~(1<<SMD_DATA1_PIN); // Data 1, input
+ SMD_DATA_PORT_DDR &= ~(1<<SMD_DATA2_PIN); // Data 2, input
+ SMD_DATA_PORT_DDR &= ~(1<<SMD_DATA3_PIN); // Data 3, input
+ SMD_DATA_PORT_DDR &= ~(1<<SMD_DATA4_PIN); // Data 4, input
+ SMD_DATA_PORT_DDR &= ~(1<<SMD_DATA5_PIN); // Data 5, input
+ SMD_DATA_PORT_PORT |= 1<<SMD_DATA0_PIN; // Data 0, pull-up
+ SMD_DATA_PORT_PORT |= 1<<SMD_DATA1_PIN; // Data 1, pull-up
+ SMD_DATA_PORT_PORT |= 1<<SMD_DATA2_PIN; // Data 2, pull-up
+ SMD_DATA_PORT_PORT |= 1<<SMD_DATA3_PIN; // Data 3, pull-up
+ SMD_DATA_PORT_PORT |= 1<<SMD_DATA4_PIN; // Data 4, pull-up
+ SMD_DATA_PORT_PORT |= 1<<SMD_DATA5_PIN; // Data 5, pull-up
+}
+
+uint16_t get_smd_gamepad()
+{
+ uint8_t gamepad_data_low = 0;
+ uint8_t gamepad_data_high = 0;
+ SMD_SELECT_PORT_PORT &= ~(1<<SMD_SELECT_PIN); // Select - low
+ _delay_us(50);
+ gamepad_data_low = ((SMD_DATA_PORT_PIN>>SMD_DATA0_PIN)&1)
+ | (((SMD_DATA_PORT_PIN>>SMD_DATA1_PIN)&1)<<1)
+ | (((SMD_DATA_PORT_PIN>>SMD_DATA2_PIN)&1)<<2)
+ | (((SMD_DATA_PORT_PIN>>SMD_DATA3_PIN)&1)<<3)
+ | (((SMD_DATA_PORT_PIN>>SMD_DATA4_PIN)&1)<<4)
+ | (((SMD_DATA_PORT_PIN>>SMD_DATA5_PIN)&1)<<5);
+ SMD_SELECT_PORT_PORT |= 1<<SMD_SELECT_PIN; // Select - high
+ _delay_us(50);
+ gamepad_data_high = ((SMD_DATA_PORT_PIN>>SMD_DATA0_PIN)&1)
+ | (((SMD_DATA_PORT_PIN>>SMD_DATA1_PIN)&1)<<1)
+ | (((SMD_DATA_PORT_PIN>>SMD_DATA2_PIN)&1)<<2)
+ | (((SMD_DATA_PORT_PIN>>SMD_DATA3_PIN)&1)<<3)
+ | (((SMD_DATA_PORT_PIN>>SMD_DATA4_PIN)&1)<<4)
+ | (((SMD_DATA_PORT_PIN>>SMD_DATA5_PIN)&1)<<5);
+ return ((uint16_t)gamepad_data_high<<8) | gamepad_data_low;
+}
+#endif
+
+#ifdef DUALSHOCK_ENABLED
+void init_dualshock_gamepad()
+{
+ DUALSHOCK_PORT_DDR |= (1<<DUALSHOCK_COMMAND_PIN); // Command pin - output
+ DUALSHOCK_PORT_PORT |= (1<<DUALSHOCK_COMMAND_PIN); // Command pin - login high
+ DUALSHOCK_PORT_DDR &= ~(1<<DUALSHOCK_DATA_PIN); // Data pin - input
+ DUALSHOCK_PORT_PORT |= (1<<DUALSHOCK_DATA_PIN); // Data pin - pull-up
+ DUALSHOCK_PORT_DDR |= (1<<DUALSHOCK_ATTENTION_PIN); // Attention - output
+ DUALSHOCK_PORT_PORT |= (1<<DUALSHOCK_ATTENTION_PIN); // Attention - logic high
+ DUALSHOCK_PORT_DDR |= (1<<DUALSHOCK_CLOCK_PIN); // Clock - output
+ DUALSHOCK_PORT_PORT |= (1<<DUALSHOCK_CLOCK_PIN); // Clock - logic high
+ /*
+ DUALSHOCK_PORT_DDR &= ~(1<<DUALSHOCK_ACK_PIN); // Ack pin - input
+ DUALSHOCK_PORT_PORT |= (1<<DUALSHOCK_ACK_PIN); // Ack pin - pull-up
+ */
+}
+
+int dualshock_command(uint8_t* command, uint8_t* data, int length)
+{
+ DUALSHOCK_PORT_PORT &= ~(1<<DUALSHOCK_ATTENTION_PIN); // Attention!
+ _delay_us(20);
+ int b, bit;
+ for (b = 0; b < length; b++) // Each byte...
+ {
+ data[b] = 0;
+ for (bit = 0; bit < 8; bit++)
+ {
+ if ((command[b] >> bit) & 1) // 1?
+ DUALSHOCK_PORT_PORT |= (1<<DUALSHOCK_COMMAND_PIN); // 1!
+ else DUALSHOCK_PORT_PORT &= ~(1<<DUALSHOCK_COMMAND_PIN); // 0!
+ DUALSHOCK_PORT_PORT &= ~(1<<DUALSHOCK_CLOCK_PIN); // Clock - logic low
+ _delay_us(20);
+ if ((DUALSHOCK_PORT_PIN >> DUALSHOCK_DATA_PIN) & 1) // Reading data... 1?
+ data[b] |= (1<<bit); // 1!
+ DUALSHOCK_PORT_PORT |= (1<<DUALSHOCK_CLOCK_PIN); // Clock - logic high
+ _delay_us(20);
+ }
+ if (b == 1 && data[1] == 0xFF) // Alternative device detection
+ {
+ DUALSHOCK_PORT_PORT |= (1<<DUALSHOCK_ATTENTION_PIN); // No attention...
+ return 0;
+ }
+ /*
+ if (b<length-1) // Waiting for ACK
+ {
+ int t;
+ for (t = 0; t < 50; t++)
+ {
+ if (!((DUALSHOCK_PORT_PIN >> DUALSHOCK_ACK_PIN)&1)) // ACK reveived
+ {
+ ok = 1;
+ break;
+ }
+ _delay_us(1);
+ }
+ if ((b < 2) && !ok) return 0; // No ACK in first two bytes? Aboooort! Saving time
+ }
+ */
+ }
+ DUALSHOCK_PORT_PORT |= (1<<DUALSHOCK_ATTENTION_PIN); // No attention...
+ _delay_us(20);
+ return 1;
+}
+
+int get_dualshock_gamepad(uint8_t* data, int size, uint8_t motor_small, uint8_t motor_large) // pointer to uint8_t[21], number of bytes to request, vibration...
+{
+ static char dualshock_configered = 0;
+
+ uint8_t command_query[21] = {0x01, 0x42, 0, motor_small, motor_large, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+ if (!dualshock_command(command_query, data, size))
+ {
+ dualshock_configered = 0;
+ return 0;
+ }
+ if (!dualshock_configered) // Need to reconfigure dualshock
+ {
+ uint8_t command_config_mode[5] = {0x01, 0x43, 0x00, 0x01, 0x00};
+ if (!dualshock_command(command_config_mode, data, sizeof(command_config_mode))) return 0;
+ uint8_t command_analog_mode[9] = {0x01, 0x44, 0x00, 0x01, 0x03, 0x00, 0x00, 0x00, 0x00};
+ if (!dualshock_command(command_analog_mode, data, sizeof(command_analog_mode))) return 0;
+ uint8_t command_config_motors[9] = {0x01, 0x4D, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF};
+ if (!dualshock_command(command_config_motors, data, sizeof(command_config_motors))) return 0;
+ uint8_t command_config_pressure[9] = {0x01, 0x4F, 0x00, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00};
+ if (!dualshock_command(command_config_pressure, data, sizeof(command_config_pressure))) return 0;
+ uint8_t command_config_mode_exit[8] = {0x01, 0x43, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF};
+ if (!dualshock_command(command_config_mode_exit, data, sizeof(command_config_mode_exit))) return 0;
+ dualshock_configered = 1;
+ if (!dualshock_command(command_query, data, size)) return 0;
+ }
+ return 1;
+}
+#endif
diff --git a/gamepad.h b/gamepad.h
new file mode 100644
index 0000000..c3592a8
--- /dev/null
+++ b/gamepad.h
@@ -0,0 +1,54 @@
+#ifndef _GAMEPAD_H_
+#define _GAMEPAD_H_
+
+#include <inttypes.h>
+#include "defines.h"
+
+#define GLUE(a,b) a##b
+#define DDR(p) GLUE(DDR,p)
+#define PORT(p) GLUE(PORT,p)
+#define PIN(p) GLUE(PIN,p)
+
+#define N64_PORT_PORT PORT(N64_PORT)
+#define N64_PORT_DDR DDR(N64_PORT)
+#define N64_PORT_PIN PIN(N64_PORT)
+
+#define NES_PORT_PORT PORT(NES_PORT)
+#define NES_PORT_DDR DDR(NES_PORT)
+#define NES_PORT_PIN PIN(NES_PORT)
+
+#define SNES_PORT_PORT PORT(SNES_PORT)
+#define SNES_PORT_DDR DDR(SNES_PORT)
+#define SNES_PORT_PIN PIN(SNES_PORT)
+
+#define SMD_SELECT_PORT_PORT PORT(SMD_SELECT_PORT)
+#define SMD_SELECT_PORT_DDR DDR(SMD_SELECT_PORT)
+#define SMD_DATA_PORT_PORT PORT(SMD_DATA_PORT)
+#define SMD_DATA_PORT_DDR DDR(SMD_DATA_PORT)
+#define SMD_DATA_PORT_PIN PIN(SMD_DATA_PORT)
+
+#define DUALSHOCK_PORT_PORT PORT(DUALSHOCK_PORT)
+#define DUALSHOCK_PORT_DDR DDR(DUALSHOCK_PORT)
+#define DUALSHOCK_PORT_PIN PIN(DUALSHOCK_PORT)
+
+#define WAIT(t) {TCNT0=0; while(TCNT0 < (F_CPU / 1000000UL) * t);}
+
+#define N64SEND(t) {N64_PORT_DDR |= (1<<N64_DATA_PIN); WAIT(t); N64_PORT_DDR &= ~(1<<N64_DATA_PIN);}
+#define N64SEND_1 {N64SEND(1); WAIT(3);}
+#define N64SEND_0 {N64SEND(3); WAIT(1);}
+#define N64SEND_STOP {N64SEND(1); WAIT(2);}
+#define N64SIGNAL (!((N64_PORT_PIN>>N64_DATA_PIN)&1))
+
+void init_nes_gamepad();
+uint8_t get_nes_gamepad();
+void init_snes_gamepad();
+uint16_t get_snes_gamepad();
+void init_n64_gamepad();
+int get_n64_gamepad(uint8_t* data);
+void init_smd_gamepad();
+uint16_t get_smd_gamepad();
+void init_dualshock_gamepad();
+int dualshock_command(uint8_t* command, uint8_t* data, int length);
+int get_dualshock_gamepad(uint8_t* data, int size, uint8_t motor_small, uint8_t motor_large);
+
+#endif
diff --git a/snes2nes.c b/snes2nes.c
new file mode 100644
index 0000000..36ad907
--- /dev/null
+++ b/snes2nes.c
@@ -0,0 +1,140 @@
+#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 - на ввод
+/*
+ DDRB = 0; // Кнопки на ввод
+ PORTB = 0xFF; // Подтяжка кнопок
+ unset_bit3(DDRD, 5, 6, 7); // Кнопки на ввод
+ set_bit3(PORTD, 5, 6, 7); // Подтяжка кнопок
+*/
+ 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++;
+ }
+}
+
+
diff --git a/snes2nes.hex b/snes2nes.hex
new file mode 100644
index 0000000..63d8a11
--- /dev/null
+++ b/snes2nes.hex
@@ -0,0 +1,60 @@
+:1000000012C022C043C01FC01EC01DC01CC01BC0E8
+:100010001AC019C018C017C016C015C014C013C02C
+:1000200012C011C010C011241FBECFE5D4E0DEBF46
+:10003000CDBF10E0A0E6B0E001C01D92A336B1072D
+:10004000E1F798D0ACC1DCCF1F920F920FB60F92A0
+:1000500011248F939F9380916000880F809360009C
+:100060009091620080916000892341F490989F9163
+:100070008F910F900FBE0F901F901895909A9F919F
+:100080008F910F900FBE0F901F9018951F920F9297
+:100090000FB60F9211248F939F9381E0809360009D
+:1000A0009091620080916000892341F490989F9123
+:1000B0008F910F900FBE0F901F901895909A9F915F
+:1000C0008F910F900FBE0F901F901895FF920F9376
+:1000D0001F93CF93DF9314E0C8ECD0E088B381275F
+:1000E00088BB24EF31E0CE010197F1F72150304079
+:1000F000D1F70AD19F708F5F9F4081F7C29A20EDA0
+:1001000037E048EC50E0CA010197F1F72150304048
+:10011000D1F700E010E084E0F82EC8ECD0E088B31E
+:100120008F2588BB24EF31E0CE010197F1F72150F4
+:100130003040D1F7E9D0BC019F708F5F9F40B9F08C
+:100140000F5F1F4F0E31110554F3C29A28E833E1B7
+:1001500048EC50E0CA010197F1F721503040D1F747
+:10016000CB01DF91CF911F910F91FF90089500E097
+:1001700010E0D5CF4F925F927F928F929F92AF9275
+:10018000BF92CF92DF92EF92FF920F931F93DF9374
+:10019000CF9300D000D0CDB7DEB7889A81B3837FEC
+:1001A00081BBBA9A85B78C6085BF85B7836085BFF0
+:1001B0008BB780648BBF8BB780688BBF78949FD0E0
+:1001C0008FEF9FE09A8389839C838B8323E0422E69
+:1001D000512C4C0E5D1EC20160E070E042E050E028
+:1001E000B8D04E010894811C911CC40162E070E0FB
+:1001F00042E050E0AED0EE24FF2477247A9490E2DF
+:10020000A92E9EE4B92E4FC0C29887E00B3F180775
+:1002100029F08BE00B3F180709F052C067010894E2
+:10022000C11CD11C88ECE816F10409F44CC033FD64
+:1002300004C08B819C812823392332FD04C089812D
+:100240009A8128233923922F432F4170822F817066
+:10025000880F482B9C7F492B31FD08C0809161009D
+:1002600090E08770907004970CF44E7F21FD08C0D9
+:100270008091610090E08770907004970CF44D7F3E
+:1002800027FD02C026FF406825FD02C024FF406212
+:1002900040936200C5010197F1F7809161008F5F83
+:1002A00080936100760130D09C018C011F708FE03B
+:1002B0000F3F180709F0A8CFC29ACC24DD24B7CF8E
+:1002C000CC24DD24B4CF7092620000DF9C600B5F11
+:1002D000174061F09A838983C40162E070E042E0D4
+:1002E00050E047D04FEF2FEF3FE0CECF9C838B8382
+:1002F000C20160E070E042E050E03BD0F3CFBB9A37
+:10030000BC9ABD98C59A0895C39840E050E020E09B
+:1003100030E06AE1C498862F8A95F1F786B382951A
+:100320008695877090E081709070022E02C0880FD1
+:10033000991F0A94E2F7482B592BC49A862F8A9565
+:10034000F1F72F5F3F4F2031310521F7C39ACA01E2
+:100350000895DC01CB01FC01E199FECF06C0FFBB93
+:10036000EEBBE09A31960DB20D9241505040B8F775
+:100370000895DC01CB0102C02D9105D041505040C1
+:10038000D8F70895262FE199FECF9FBB8EBB2DBBDA
+:100390000FB6F894E29AE19A0FBE01960895F89488
+:0203A000FFCF8D
+:00000001FF
diff --git a/snes2nes.lay6 b/snes2nes.lay6
new file mode 100644
index 0000000..d81101e
--- /dev/null
+++ b/snes2nes.lay6
Binary files differ