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.
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.
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.
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
git clone git://github.com/lowlander/m3_sid.git
git clone git://github.com/lowlander/sid_bridge.git