In 2020 I made a SID player based on a Lattice MachXO2 that was connected via SPI to a STM32G4 board running Zephyr.
Now I got a Trenz SMF2000 board that has a Microsemi SmartFusion2 that has a Cortex M3 and a FPGA on one chip, so connecting the CPU to the FPGA is a lot easier. Instead of going via SPI from CPU to FPGA, it is possible to use a AHB bus to connect the CPU to the FPGA fabric. The connection from the FPGA to the SID chip still needs the 5 address + 8 data + clk + cs + rw + rst = 17 pins like with the previous setup.
This reduces the amount of hardware a lot, although the comparison isn’t entirely fair, the STM32G4 is a Cortex M4 with more RAM resources on chip, but the SMF2000 board has an extra 8MByte SDRAM chip to compensate for the only 64 kbyte on chip SRAM.
SID player
The actual SID player is pretty much the same as described in my previous post, it is basically a C64 emulator that plays a compiled in C64 SID file. The difference with last time is that now the CPU can simply write to a memory address to access the SID chip, no need to go through a SPI driver, this makes to code a lot easier. To make the hardware design easier the CPU uses 32bit wide access, where the C64/SID only has a 8bit bus. The FPGA wil only send the lower 8 data bits to the SID. the address space is divided in two blocks, the actual SID access space starting at 0xC000
and the register space starting at 0x0000
. The SID space just holds the SID registers, with the difference they are 32bit aligned, so SID reg 0x00
is on 0xc000
, SID reg 0x01
is on 0xc004
, SID reg 0x02
is on 0xc008
, etc. etc. The register address space currently only has two register on address 0x0000
, where the first bit sets and clears the reset pin of the SID, and on 0x0004
where the frequency divider that is used to tune the SID clock frequency.
Another difference with the last version is that Zephyr isn’t used, but instead the auto generated code project that the Microsemi tools offer, that was good enough for this demo.
FPGA
Like the SID player software the FPGA implementation became a lot simpler since there is no need for a SPI slave implementation. It is basically a bridge from the AHB bus to the slower SID CS interface.
Since the SID needs a ~1MHz clock (see my previous post for more details), the sid_bridge
component generates that from the 71MHz AHB clock. The read and write access are then synchronized to that 1 MHz clock, which means the AHB bus must wait until the SID is ready. For the rest it is just a really simple state machine that only handles 32bit single word bus accesses, that are translated to the 8bit SID bus accesses.
8Mbyte SDRAM
The SID player uses a 64kByte RAM buffer to emulate the C64 address space, but the SOC on the SMF2000 only has 64kByte memory, so there would not be any memory left to run the program. So the external 8MByte SDRAM was needed, but that didn’t want to work. There are several posts in the Trenz Forum where people also have problems to get it working. In the end I got it working by using a bit of a different setup than most examples show, by using the CORESDR_AHB
bridge instead of the AXI bridge. The biggest difference is that it is mapped to a different address 0x5000_0000
and not to 0xA000_0000
, but for the rest it seems to work.
And to test it all lets play a tune (Cantina Band, by Markus Klein) on the SMF2000. There are still some problems with the analog audio part, first of all the SID filters are not working correctly (they might be broken due to all the experimenting I did with this chip) and the power supply is not optimal, the Vdd is only 5V and it should be something like 9 to 12V. But the digital interface works, and it produces sound.
Getting the Source Code
The source code is of course available on GitHub. The SID player m3_sid and the FPGA sid_bridge can be cloned using the following git commands
git clone git://github.com/lowlander/m3_sid.git
and
git clone git://github.com/lowlander/sid_bridge.git
Feedback
Feel free to give feedback on Linkedin