I wrote a mandelbrot calculator in assembly within 2KB.
Four aspects are maybe worth mentioning and interessting to others.
speed:
The inner mandelbrot loop is pretty optimized for speed.
It uses fixpoint math so it all comes down to few integer
multiplications and shifts.
Also when you scroll the area with LEFT/RIGHT/UP/DOWN
only the area that was formerly not seen gets calculated.
This is why zooming with BUTTON A/B is slower than scrolling as a full image needs to be recomputed.
The iteration (= depth of the fractal) is increased automatically when you zoom in (out) but you can also manually control that with the right pad UP/DOWN. Zooming should halt
automatically when you reach the limit of the fixpoint resolution which was set to 2.13+sign so a multiplication still fits into 32bit.
size:
The main body of the code is compressed with lz4 and depacked into RAM at start. While lz4 is not a very strong compression it is simple to decode and the decompressor fits nicely along other routines in the upper part of the ROM (between the RESET vector and the ROM header to fill that often wasted space).
I published the decoder here:
https://github.com/enthusi/lz4_v810_decode
I optimized several aspects of the code to eventually fit the 2k size limit. The lz4 helped to get it just into 2k.
shades:
The mandelbrot is drawn in the usual way (color the pixels based on ‘how soon they escape the region of convergence’).
But since this looks rather boring in 4 colors I added a dither pattern leading to 13 different shades. This is based on a simple 2×2 dither as you can tell from the visuals.
gfx mode:
Writing directly into framebuffer has a couple of disadvantages:
– each byte contains 4 pixels so the bus reads/writes 8 pixels at a time and alot of shifting and/or eoring is required.
– writing ~ 21KB into both buffers is kinda slow.
– 2×2 dithering would seriously render this more complex and much slower.
Therefor I tried an approach I had thought about for some other project and used this occasion to test it.
I store the pixels into a world tile map but scale it to 25%.
So a 8×8 char becomes 2×2 pixels large. This is awesome as I can directly place one of 13 shades (2×2) dither with a single write. The downside is that I need to set up 3×2 affine worlds all scaled to 25% to cover the whole screen area.
The effective screen resolution is 192×112 pixels now but I think it really looks nice on real hardware and with the full resolution dither this looks even better than I had hoped for.
Drawing 6 affine worlds isnt exactly fast but the computational time of the mandelbrot is still the dominant source of slowliness by far. The mandel algo stores into a 8 bit aligned linear buffer to avoid pixel-adress math for every point. This buffer is then blitted into the worldmaps.
The color cycle you see simply rotates the 14 characters every frame. That’s just a couple of bytes to copy.
Find attached the 2kb binary.
It is also available here:
http://enthusi.de/man.zip
Cheers,
enthusi
- This topic was modified 3 years, 3 months ago by enthusi.
- This topic was modified 3 years, 3 months ago by enthusi.
- This topic was modified 3 years, 3 months ago by enthusi.
- This topic was modified 3 years, 3 months ago by KR155E. Reason: Added tag for featuring on front page
- This topic was modified 3 years, 3 months ago by KR155E. Reason: Attached screenshot to prevent mixed content errors