diff options
author | Alexey 'Cluster' Avdyukhin <clusterrr@clusterrr.com> | 2015-11-06 08:36:40 +0300 |
---|---|---|
committer | Alexey 'Cluster' Avdyukhin <clusterrr@clusterrr.com> | 2015-11-06 08:36:40 +0300 |
commit | f9222dc2fe7c1bd21af85da31db292048559feaf (patch) | |
tree | 6c3c6c8c8ecf3ce26bb09ab43299d28978cc560a |
First commit
-rw-r--r-- | Makefile | 148 | ||||
-rw-r--r-- | bits.h | 12 | ||||
-rw-r--r-- | defines.h | 8 | ||||
-rw-r--r-- | gamepad.c | 223 | ||||
-rw-r--r-- | gamepad.h | 54 | ||||
-rw-r--r-- | snes2nes.c | 140 | ||||
-rw-r--r-- | snes2nes.hex | 60 | ||||
-rw-r--r-- | snes2nes.lay6 | bin | 0 -> 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 @@ -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 Binary files differnew file mode 100644 index 0000000..d81101e --- /dev/null +++ b/snes2nes.lay6 |