FPGABee v3.0

Sound

Now the video controller was sorted out and FPGABee was functional enough to run a game that I wrote back in the 80's, but there was no sound. In this article FPGABee gets a speaker.

Microbee Sound Interface

The Microbee's sound interface is extremely simple - bit 6 on I/O port 2 is wired to the speaker, so toggling that bit will also toggle the speaker. Toggle it at a suitable frequency and you get sound.

In a real Microbee, port 2 is actually connected to the PIO - a Programmable I/O chip that also handled tape I/O and other I/O responsibilities.

For the purposes of the speaker, FPGABee doesn't need the PIO so I'll be ignoring that for now.

Giving the Nexys 3 a Speaker

The first step in getting sound working was to figure out how to actually connect a speaker to the Nexys 3 board. Theoretically it might be possible for the Spartan chip to drive the speaker directly but I didn't want to risk it so I borrowed the circuitry from the Microbee and hooked it up through a transistor:

Microbee Speaker Circuit

Since I don't have 10V handy, I picked up the 3.3V from the Nexys' PMod connector and adjusted R27 down to 15K. Although the speaker is currently connected to it's own PMod port, I decided to use PMod pin 3 since this would allow putting both the speaker and keyboard (which uses pins 2 and 4) on the one PMod connector later if necessary.

Here it is:

DSC_0031.jpg

Implementing Port 2

The PIO port, port 2 needs to support both "in" and "out" operations, so I used a register to store it's state:

signal pio_port_b : STD_LOGIC_VECTOR(7 downto 0);

Connect the port write:

-- Write to port 2 (PIO port B)
if (z80_addr(7 downto 0)=x"02" and port_wr = '1') then
    pio_port_b <= z80_dout;
end if;

Connect the port read:

z80_din <=  x"00" when (boot_scan = '1') else
        -- other assignments omitted
        pio_port_b when (port_rd='1' and (z80_addr(7 downto 0) = x"02")) else
        x"00";

And finally connect bit 6 to the correct pin on the Spartan chip:

speaker <= pio_port_b(6);

Here's the declaration in the UCF file that specifies which design ports go where. JB3 is pin 3 on the second PMod connector:

Net "speaker" LOC = L4 |IOSTANDARD = LVCMOS33; #Bank = 3, pin name = IO_L39P_M3LDQS, Sch name = JB3

That's It

Pretty simple and it worked first go. I heard the familiar Microworld Basic boot beep and running Robot Fire made the appropriate noises. It's a little quieter than a real Microbee, but that's a good thing.