Skip to content

Commit

Permalink
[WIRED] Add NES/SNES PISO driver
Browse files Browse the repository at this point in the history
  • Loading branch information
darthcloud committed Jul 25, 2020
1 parent 42de0a0 commit daa0c1c
Show file tree
Hide file tree
Showing 4 changed files with 363 additions and 2 deletions.
1 change: 1 addition & 0 deletions main/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ idf_component_register(SRCS "main.c"
"bluetooth/hidp_sw.c"
"drivers/sd.c"
"wired/detect.c"
"wired/npiso.c"
"wired/sega_io.c"
"wired/nsi.c"
"wired/maple.c"
Expand Down
5 changes: 3 additions & 2 deletions main/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "adapter/config.h"
#include "bluetooth/host.h"
#include "wired/detect.h"
#include "wired/npiso.h"
#include "wired/sega_io.h"
#include "wired/nsi.h"
#include "wired/maple.h"
Expand All @@ -30,11 +31,11 @@ static const char *sys_name[WIRED_MAX] = {

static const wired_init_t wired_init[WIRED_MAX] = {
NULL,
NULL,
npiso_init,
NULL,
NULL,
sega_io_init,
NULL,
npiso_init,
NULL,
sega_io_init,
nsi_init,
Expand Down
353 changes: 353 additions & 0 deletions main/wired/npiso.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,353 @@
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <xtensa/hal.h>
#include <esp_intr_alloc.h>
#include "driver/gpio.h"
#include "../zephyr/types.h"
#include "../util.h"
#include "../adapter/adapter.h"
#include "../adapter/config.h"
#include "npiso.h"

#define NPISO_PORT_MAX 2
#define NPISO_LATCH_PIN 32
#define NPISO_LATCH_MASK (1U << 0) /* First of 2nd bank of GPIO */
#define NPISO_TIMEOUT 4096

enum {
NPISO_CLK = 0,
NPISO_SEL,
NPISO_D0,
NPISO_D1,
NPISO_PIN_MAX,
};

enum {
DEV_NONE = 0,
DEV_FC_NES_PAD,
DEV_FC_NES_MULTITAP,
DEV_FC_MULTITAP_ALT,
DEV_FC_TRACKBALL,
DEV_FC_KB,
DEV_SFC_SNES_PAD,
DEV_SFC_SNES_MULTITAP,
DEV_SFC_SNES_MOUSE,
DEV_SNES_XBAND_KB,
};

static const uint8_t gpio_pins[NPISO_PORT_MAX][NPISO_PIN_MAX] = {
{ 5, 23, 19, 21},
{18, 26, 22, 25},
};

static const uint32_t gpio_mask[NPISO_PORT_MAX][NPISO_PIN_MAX] = {
{(1U << 5), (1U << 23), (1U << 19), (1U << 21)},
{(1U << 18), (1U << 26), (1U << 22), (1U << 25)},
};

static uint8_t dev_type[NPISO_PORT_MAX] = {0};
static uint8_t mt_first_port[NPISO_PORT_MAX] = {0};
static uint8_t buffer[8];
static uint32_t cnt[2] = {0};
static uint8_t mask[2] = {0x80, 0x80};

static void IRAM_ATTR set_data(uint8_t port, uint8_t data_id, uint8_t value) {
uint8_t pin = gpio_pins[port][NPISO_D0 + data_id];

if (value) {
GPIO.out_w1ts = BIT(pin);
}
else {
GPIO.out_w1tc = BIT(pin);
}
}

static void IRAM_ATTR npiso_fc_nes_2p_isr(void* arg) {
const uint32_t low_io = GPIO.acpu_int;
const uint32_t high_io = GPIO.acpu_int1.intr;

/* reset bit counter, set first bit */
if (high_io & NPISO_LATCH_MASK) {
set_data(0, 0, wired_adapter.data[0].output[0] & 0x80);
set_data(1, 0, wired_adapter.data[1].output[0] & 0x80);
cnt[0] = 1;
cnt[1] = 1;
mask[0] = 0x40;
mask[1] = 0x40;
}

/* Update port 0 */
if (low_io & gpio_mask[0][NPISO_CLK]) {
if (cnt[0] > 7) {
set_data(0, 0, 0);
}
else {
set_data(0, 0, wired_adapter.data[0].output[0] & mask[0]);
}
cnt[0]++;
mask[0] >>= 1;
}

/* Update port 1 */
if (low_io & gpio_mask[1][NPISO_CLK]) {
if (cnt[1] > 7) {
set_data(1, 0, 0);
}
else {
set_data(1, 0, wired_adapter.data[1].output[0] & mask[1]);
}
cnt[1]++;
mask[1] >>= 1;
}

if (high_io) GPIO.status1_w1tc.intr_st = high_io;
if (low_io) GPIO.status_w1tc = low_io;
}

static void IRAM_ATTR npiso_fc_4p_isr(void* arg) {
const uint32_t low_io = GPIO.acpu_int;
const uint32_t high_io = GPIO.acpu_int1.intr;

/* reset bit counter, set first bit */
if (high_io & NPISO_LATCH_MASK) {
set_data(0, 0, wired_adapter.data[0].output[0] & 0x80);
set_data(1, 0, wired_adapter.data[1].output[0] & 0x80);
set_data(0, 1, wired_adapter.data[2].output[0] & 0x80);
set_data(1, 1, wired_adapter.data[3].output[0] & 0x80);
cnt[0] = 1;
cnt[1] = 1;
mask[0] = 0x40;
mask[1] = 0x40;
}

/* Update port 0 */
if (low_io & gpio_mask[0][NPISO_CLK]) {
if (cnt[0] > 7) {
set_data(0, 0, 0);
set_data(0, 1, 0);
}
else {
set_data(0, 0, wired_adapter.data[0].output[0] & mask[0]);
set_data(0, 1, wired_adapter.data[2].output[0] & mask[0]);
}
cnt[0]++;
mask[0] >>= 1;
}

/* Update port 1 */
if (low_io & gpio_mask[1][NPISO_CLK]) {
if (cnt[1] > 7) {
set_data(1, 0, 0);
set_data(1, 1, 0);
}
else {
set_data(1, 0, wired_adapter.data[1].output[0] & mask[1]);
set_data(1, 1, wired_adapter.data[3].output[0] & mask[1]);
}
cnt[1]++;
mask[1] >>= 1;
}

if (high_io) GPIO.status1_w1tc.intr_st = high_io;
if (low_io) GPIO.status_w1tc = low_io;
}

static void IRAM_ATTR npiso_nes_fs_isr(void* arg) {
const uint32_t low_io = GPIO.acpu_int;
const uint32_t high_io = GPIO.acpu_int1.intr;
uint32_t idx0, idx1;

/* reset bit counter, set first bit */
if (high_io & NPISO_LATCH_MASK) {
set_data(0, 0, wired_adapter.data[0].output[0] & 0x80);
set_data(1, 0, wired_adapter.data[1].output[0] & 0x80);
cnt[0] = 1;
cnt[1] = 1;
mask[0] = 0x40;
mask[1] = 0x40;
}

idx0 = cnt[0] >> 3;
idx1 = cnt[1] >> 3;

/* Update port 0 */
if (low_io & gpio_mask[0][NPISO_CLK]) {
switch (idx0) {
case 0:
set_data(0, 0, wired_adapter.data[0].output[0] & mask[0]);
break;
case 1:
set_data(0, 0, wired_adapter.data[2].output[0] & mask[0]);
break;
case 2:
set_data(0, 0, 0xEF & mask[0]);
break;
default:
set_data(0, 0, 0);
break;
}
cnt[0]++;
mask[0] >>= 1;
if (!mask[0]) {
mask[0] = 0x80;
}
}

/* Update port 1 */
if (low_io & gpio_mask[1][NPISO_CLK]) {
switch (idx1) {
case 0:
set_data(1, 0, wired_adapter.data[1].output[0] & mask[1]);
break;
case 1:
set_data(1, 0, wired_adapter.data[3].output[0] & mask[1]);
break;
case 2:
set_data(1, 0, 0xDF & mask[1]);
break;
default:
set_data(1, 0, 0);
break;
}
cnt[1]++;
mask[1] >>= 1;
if (!mask[1]) {
mask[1] = 0x80;
}
}

if (high_io) GPIO.status1_w1tc.intr_st = high_io;
if (low_io) GPIO.status_w1tc = low_io;
}

void npiso_init(void)
{
gpio_config_t io_conf = {0};

if (wired_adapter.system_id == NES) {
switch (config.global_cfg.multitap_cfg) {
case MT_SLOT_1:
case MT_SLOT_2:
case MT_DUAL:
dev_type[0] = DEV_FC_NES_MULTITAP;
dev_type[1] = DEV_FC_NES_MULTITAP;
mt_first_port[1] = 2;
break;
case MT_ALT:
dev_type[0] = DEV_FC_MULTITAP_ALT;
dev_type[1] = DEV_FC_MULTITAP_ALT;
break;
default:
mt_first_port[1] = 1;
break;
}

for (uint32_t i = 0; i < NPISO_PORT_MAX; i++) {
if (dev_type[i] == DEV_NONE) {
switch (config.out_cfg[i].dev_mode) {
case DEV_PAD:
case DEV_PAD_ALT:
dev_type[i] = DEV_FC_NES_PAD;
break;
case DEV_KB:
dev_type[i] = DEV_FC_KB;
break;
case DEV_MOUSE:
dev_type[i] = DEV_FC_TRACKBALL;
break;
}
}
}
}
else {
switch (config.global_cfg.multitap_cfg) {
case MT_SLOT_1:
dev_type[0] = DEV_SFC_SNES_MULTITAP;
mt_first_port[1] = 4;
break;
case MT_SLOT_2:
dev_type[1] = DEV_SFC_SNES_MULTITAP;
mt_first_port[1] = 1;
break;
case MT_DUAL:
dev_type[0] = DEV_SFC_SNES_MULTITAP;
dev_type[1] = DEV_SFC_SNES_MULTITAP;
mt_first_port[1] = 4;
break;
default:
mt_first_port[1] = 1;
break;
}

for (uint32_t i = 0; i < NPISO_PORT_MAX; i++) {
if (dev_type[i] == DEV_NONE) {
switch (config.out_cfg[i].dev_mode) {
case DEV_PAD:
case DEV_PAD_ALT:
dev_type[i] = DEV_SFC_SNES_PAD;
break;
case DEV_KB:
dev_type[i] = DEV_SNES_XBAND_KB;
break;
case DEV_MOUSE:
dev_type[i] = DEV_SFC_SNES_MOUSE;
break;
}
}
}
}

/* Latch */
io_conf.intr_type = GPIO_PIN_INTR_POSEDGE;
io_conf.pin_bit_mask = 1ULL << NPISO_LATCH_PIN;
io_conf.mode = GPIO_MODE_INPUT;
io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
io_conf.pull_up_en = GPIO_PULLUP_DISABLE;
gpio_config(&io_conf);

/* Clocks */
for (uint32_t i = 0; i < NPISO_PORT_MAX; i++) {
io_conf.intr_type = GPIO_PIN_INTR_POSEDGE;
io_conf.pin_bit_mask = 1ULL << gpio_pins[i][NPISO_CLK];
io_conf.mode = GPIO_MODE_INPUT;
io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
io_conf.pull_up_en = GPIO_PULLUP_ENABLE;
gpio_config(&io_conf);
}

/* Selects */
for (uint32_t i = 0; i < NPISO_PORT_MAX; i++) {
io_conf.intr_type = GPIO_PIN_INTR_DISABLE;
io_conf.pin_bit_mask = 1ULL << gpio_pins[i][NPISO_SEL];
io_conf.mode = GPIO_MODE_INPUT;
io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
io_conf.pull_up_en = GPIO_PULLUP_ENABLE;
gpio_config(&io_conf);
}

/* D0, D1 */
for (uint32_t i = 0; i < NPISO_PORT_MAX; i++) {
for (uint32_t j = NPISO_D0; j <= NPISO_D1; j++) {
io_conf.intr_type = GPIO_PIN_INTR_DISABLE;
io_conf.pin_bit_mask = 1ULL << gpio_pins[i][j];
io_conf.mode = GPIO_MODE_OUTPUT;
io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
io_conf.pull_up_en = GPIO_PULLUP_ENABLE;
gpio_config(&io_conf);
set_data(i, j & 0x1, 1);
}
}

if (dev_type[0] == DEV_FC_NES_MULTITAP) {
esp_intr_alloc(ETS_GPIO_INTR_SOURCE, ESP_INTR_FLAG_LEVEL3, npiso_nes_fs_isr, NULL, NULL);
}
else if (dev_type[0] == DEV_FC_MULTITAP_ALT) {
esp_intr_alloc(ETS_GPIO_INTR_SOURCE, ESP_INTR_FLAG_LEVEL3, npiso_fc_4p_isr, NULL, NULL);
}
else {
esp_intr_alloc(ETS_GPIO_INTR_SOURCE, ESP_INTR_FLAG_LEVEL3, npiso_fc_nes_2p_isr, NULL, NULL);
}
}
6 changes: 6 additions & 0 deletions main/wired/npiso.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#ifndef _NPISO_H_
#define _NPISO_H_

void npiso_init(void);

#endif /* _NPISO_H_ */

0 comments on commit daa0c1c

Please sign in to comment.