nuclear@6: #ifndef MEGADRIVE_IO_H_ nuclear@6: #define MEGADRIVE_IO_H_ nuclear@6: nuclear@7: #include nuclear@7: nuclear@7: #define IO_REG_VER *((volatile uint8_t*)0xa10001) nuclear@7: #define IO_REG_DATA1 *((volatile uint8_t*)0xa10003) nuclear@7: #define IO_REG_DATA2 *((volatile uint8_t*)0xa10005) nuclear@7: #define IO_REG_DATA3 *((volatile uint8_t*)0xa10007) nuclear@7: #define IO_REG_CTRL1 *((volatile uint8_t*)0xa10009) nuclear@7: #define IO_REG_CTRL2 *((volatile uint8_t*)0xa1000b) nuclear@7: #define IO_REG_CTRL3 *((volatile uint8_t*)0xa1000d) nuclear@7: #define IO_REG_TXDATA1 *((volatile uint8_t*)0xa1000f) nuclear@7: #define IO_REG_RXDATA1 *((volatile uint8_t*)0xa10011) nuclear@7: #define IO_REG_S_CTRL1 *((volatile uint8_t*)0xa10013) nuclear@7: #define IO_REG_TXDATA2 *((volatile uint8_t*)0xa10015) nuclear@7: #define IO_REG_RXDATA2 *((volatile uint8_t*)0xa10017) nuclear@7: #define IO_REG_S_CTRL2 *((volatile uint8_t*)0xa10013) nuclear@7: #define IO_REG_TXDATA3 *((volatile uint8_t*)0xa1001b) nuclear@7: #define IO_REG_RXDATA3 *((volatile uint8_t*)0xa1001d) nuclear@7: #define IO_REG_S_CTRL3 *((volatile uint8_t*)0xa1001f) nuclear@7: #define IO_REG_LOCK *((volatile uint8_t*)0xa14000) nuclear@7: #define IO_REG_TMSS *((volatile uint8_t*)0xa14101) nuclear@7: nuclear@8: #define IO_REG_DATA(x) *((volatile uint8_t*)0xa10003 + ((x) << 1)) nuclear@8: #define IO_REG_CTRL(x) *((volatile uint8_t*)0xa10009 + ((x) << 1)) nuclear@8: nuclear@6: nuclear@6: enum { nuclear@6: IO_VER_VERSION_MASK = 0x0f, nuclear@6: IO_VER_EXP = 0x20, nuclear@6: IO_VER_PAL = 0x40, nuclear@6: IO_VER_NONJP = 0x80 nuclear@6: }; nuclear@6: nuclear@8: enum { nuclear@11: IO_PAD_UP = 0x001, nuclear@11: IO_PAD_DOWN = 0x002, nuclear@11: IO_PAD_LEFT = 0x004, nuclear@11: IO_PAD_RIGHT = 0x008, nuclear@11: IO_PAD_B = 0x010, nuclear@11: IO_PAD_C = 0x020, nuclear@11: IO_PAD_A = 0x040, nuclear@11: IO_PAD_START = 0x080, nuclear@11: nuclear@11: IO_PAD_Z = 0x100, nuclear@11: IO_PAD_Y = 0x200, nuclear@11: IO_PAD_X = 0x400 nuclear@8: }; nuclear@10: #define IO_PAD_LOW_MASK 0x3f nuclear@10: #define IO_PAD_HIGH_MASK (IO_PAD_A | IO_PAD_START) nuclear@8: nuclear@8: static inline void io_setdir(int port, uint8_t dir) nuclear@8: { nuclear@8: IO_REG_CTRL(port) = dir; nuclear@8: } nuclear@8: nuclear@8: static inline uint16_t io_readpad(int port) nuclear@8: { nuclear@8: uint16_t bnstate; nuclear@8: nuclear@10: bnstate = ~(IO_REG_DATA(port) << 2) & IO_PAD_HIGH_MASK; nuclear@10: nuclear@8: IO_REG_DATA(port) = 0x40; /* select mode 1 */ nuclear@10: asm volatile("nop"); nuclear@10: asm volatile("nop"); nuclear@10: bnstate |= ~IO_REG_DATA(port) & IO_PAD_LOW_MASK; nuclear@10: nuclear@8: IO_REG_DATA(port) = 0; /* select mode 0 */ nuclear@10: return bnstate; nuclear@8: } nuclear@8: nuclear@11: static inline uint16_t io_readpad6(int port) nuclear@11: { nuclear@11: uint16_t bnstate; nuclear@11: nuclear@11: IO_REG_DATA(port) = 0x40; /* start with mode 1 */ nuclear@11: asm volatile("nop"); nuclear@11: asm volatile("nop"); nuclear@11: bnstate = ~IO_REG_DATA(port) & IO_PAD_LOW_MASK; nuclear@11: nuclear@11: IO_REG_DATA(port) = 0; /* select mode 0 */ nuclear@11: asm volatile("nop"); nuclear@11: asm volatile("nop"); nuclear@11: bnstate |= ~(IO_REG_DATA(port) << 2) & IO_PAD_HIGH_MASK; nuclear@11: nuclear@11: /* then introduce two more rising edges to trigger extended mode */ nuclear@11: IO_REG_DATA(port) = 0x40; nuclear@11: asm volatile("nop"); nuclear@11: asm volatile("nop"); nuclear@11: IO_REG_DATA(port) = 0; nuclear@11: asm volatile("nop"); nuclear@11: asm volatile("nop"); nuclear@11: IO_REG_DATA(port) = 0x40; nuclear@11: asm volatile("nop"); nuclear@11: asm volatile("nop"); nuclear@11: nuclear@11: bnstate |= (uint16_t)(~IO_REG_DATA(port) & 0x7) << 8; nuclear@11: IO_REG_DATA(port) = 0; /* return mode to 0 */ nuclear@11: return bnstate; nuclear@11: } nuclear@11: nuclear@10: void io_init(void); nuclear@10: /*uint16_t io_readpad(int port);*/ nuclear@10: nuclear@6: #endif /* MEGADRIVE_IO_H_ */