I have had a busy start to my senior year, and am still trying to get on top of everything. But, I believe I will be ready to give a fun demonstration during the weekly Mercury Robotics meeting on Wednesday. Here's the gist of it.
Taken from the NesDev wiki
The NES has a 48-pin expansion port on the bottom side, hidden behind a plastic panel. Of these, only a few are directly controllable by software. Therefore, in order to have fine control over a large number of peripherals, it will be necessary to add a little bit of external logic.
To this end, we have mapped the address bits 14-12 to the EXP pins, giving us access to a total of four address bits (A15 is already on the expansion port). This allows us to implement peripherals as memory-mapped IO, specifically mapped to $DXXX in our case. That is, any time the NES executes a read instruction at an address whose most significant nibble is 0xD, the external logic will wake up and execute some instruction based on the state of the signals OUT2 and OUT1.
I'll follow up with a video if this test works, but here's the snippet of FPGA code that I am loading to a DE0-Nano for the external logic. My first attempts used an Arduino, but it was ultimately too slow for this application.
-- Mercury Robotics NESbot test
-- This pairs with the NESbot demo code
-- mapping directional buttons to an RC controller.
-- Peripherals mapped to $D000
-- Controls use D2 and D1.
entity exp_to_rc is
addrClk : in std_logic; -- GPIO_00
addr : in std_logic_vector (15 downto 12); -- GPIO_01,03,05,07
contrOut : in std_logic_vector (2 downto 1); -- GPIO_02,04
goForward : out std_logic; -- GPIO_10
goBackward : out std_logic; -- GPIO_11
goLeft : out std_logic; -- GPIO_13
goRight : out std_logic; -- GPIO_15
fpgaSelect : out std_logic -- LED_0
architecture rtl of exp_to_rc is
signal TEMP_goForward : std_logic := '0';
signal TEMP_goBackward : std_logic := '0';
signal TEMP_goLeft : std_logic := '0';
signal TEMP_goRight : std_logic := '0';
signal TEMP_fpgaSelect : std_logic;
signal clk : std_logic;
fpgaSelect <= TEMP_fpgaSelect;
TEMP_fpgaSelect <= addrClk and addr(15) and addr(14)
and not addr(13) and addr(12); -- 0b1101 = 0xD
clk <= TEMP_fpgaSelect and addrClk;
goForward <= TEMP_goForward;
goBackward <= TEMP_goBackward;
goLeft <= TEMP_goLeft;
goRight <= TEMP_goRight;
if rising_edge(clk) then
TEMP_goForward <= TEMP_goForward xor ( contrOut(2) nor contrOut(1));
TEMP_goBackward <= TEMP_goBackward xor (not contrOut(2) and contrOut(1));
TEMP_goLeft <= TEMP_goLeft xor ( contrOut(2) and not contrOut(1));
TEMP_goRight <= TEMP_goRight xor ( contrOut(2) and contrOut(1));