Mandlebrot Set Generator
As I said in my last post, I implemented a Mandlebrot set generator in my STM32. Even though it was running at 64MHz, generating the set took a fair bit of time, slow enough to not even maximise the fully available SDRAM capacity at the time. At this point, I decided to give designing a fixed-point Mandlebrot set generator in VHDL. To be quite honest, it was way easier than I thought with an unoptimized version taking 224 lines of code, even less code if I get rid of the zooming feature! The square functions (x*x and y*y) take the longest combinatorially and they seem to limit the upper frequency though regardless, I can achieve slow 85deg model operation at 51MHz – more than the 48MHz that I’ll be running it at. This implementation uses 40bit wide variables organised as 24.16 fixed point. To calculate the increment value, the division by the x resolution and y resolution is converted to a multiply and shift for example:
a/640 = b
a*x/2^n ~= b
Choosing n to be some suitable large value to ensure the data doesn’t overflow and that too many bits aren’t used allows x to be found as:
2^n/x = 640
with n being 16, x can be found to be 102.4. Testing this by setting a to an arbitrary value for example 100 gives:
100/640 = 0.15625
and with the fixed point version:
100*102.4/2^16 = 0.15625
However, 102.4 isn’t an integer and would still require some form of fractional multiplier so rounding this to 102 gives:
100*102/2^16 = 0.15564
Giving a total error of 0.39%. Increasing the bit depth further decreases this error to a point where it is negligible. For this implementation, I decided to set n to 22bits.
I have read that you can implement the Mandlebrot set using a 2.xy fixed point method where you only need 2 upper bits but I’ve not managed to achieve this yet. Using the 40bit data width is pretty damn resource heavy too. Synthesizing everything consumes 61% of all FPGA resources!
For ease of all future implemented modules, I’ve modified the pixel in FIFO to work with a different in clock speed. This allows me to attach this pixel input realistically to anything.
Improved SDRAM controller
The first generation of SDRAM controller was pretty poor and was just implemented so I could get some pixels thrown on the screen! It opened and closed rows for every single read, not taking advantage of SDRAMs open row capabilities which allow reads and write to an open row within a 100us time slot. I’ve now modified the controller to keep rows activated for consecutive reads and writes and only closing the row if a new row is required or a refresh is required. This allows for much faster memory transfers and massively increased bandwidths. With these modifications, I was able to get a reasonable refresh rate out of the Mandlebrot set generator. I’ve not got any performance stats on this kind of controller but I can already see its much faster than before. Adding this row capability didn’t seem to limit the maximum operating frequency and only added a bit more logic. I needed to add an extra two states to the state machine, namely a precharge then activate state and a precharge then autorefresh state. Adding these states allowed me to use the controller with no modifications to the host side.
I’m going to see if I can get the memory interface to run at 1024×768 now and hopefully generate some much better fractals!