sylefeb
Fantastic little device! Relating to the post, I also happened to brick one erasing the Foboot bootloader by writing the flash beyond the limit (there was a bug regarding writing to addresses beyond max at the time, but then I was pushing the limit by abusing dfu-utils :) https://x.com/sylefeb/status/1391898565061001225 ). I tried to use the programming pads but at the time was lacking the skills and it ended in disaster (ripped pads...).
The code repo for the overall project is here: https://github.com/sylefeb/tinygpus
For anyone interested: I have a detailed write up on the topic here in the context of 1990s renderers https://github.com/sylefeb/tinygpus/tree/main?tab=readme-ov-... ; a video discussing texture mapping with a hardware twist https://youtu.be/2ZAIIDXoBis?si=MvQXH2ltqWmvFMdt&t=1072 ; and have a shadertoy to compare perspective correct texture mapping on/off https://www.shadertoy.com/view/ftKSzR
Tunnel effect (exactly as user bemmu described below):
- see it live: https://htmlpreview.github.io/?https://github.com/sylefeb/gf...
- lookup table: https://github.com/sylefeb/gfxcat/blob/main/tunnel/tunnel.h
- how it is computed: https://github.com/sylefeb/Silice/blob/master/projects/ice-v...
Julia fractal, with a table to do integer multiply! (2.a.b = (a+b)^2 - a^2 - b^2, so just precompute all x^2 in a table! )
- see it live: https://htmlpreview.github.io/?https://github.com/sylefeb/gf...
- code (see 'sq' table): https://github.com/sylefeb/gfxcat/blob/main/julia/julia.c
- credits (mul trick): http://cowlark.com/2018-05-26-bogomandel/index.html
In-hardware lookup division for perspective correct texturing!
- doom-chip on-ice (rC3 2021 talk): https://www.youtube.com/watch?v=2ZAIIDXoBis
- detailed write up: https://github.com/sylefeb/tinygpus?tab=readme-ov-file#preco...
- actual lookup table generation: https://github.com/sylefeb/tinygpus/blob/498be1b803d0950328a...
Sine tables are also very typical, for animating things on screen or plain trigonometry, for instance my small fixed integer raytracer uses a sine table to animate the spheres (and the cos is easy to get from the sin, especially if the table has a power of two size ;) ):
- see it live: https://htmlpreview.github.io/?https://github.com/sylefeb/gf...
- source code: https://github.com/sylefeb/gfxcat/blob/main/raytrace/raytrac...
And of course procedural textures!! Perlin noise is made of lookup tables, and often multiple lookups are combined to then lookup a clolormap (https://redirect.cs.umbc.edu/~ebert/691/Au00/Notes/procedura...)
There are so many other examples. Also, FPGAs are quite literally made of LookUp Tables, or LUTs:
- https://github.com/sylefeb/Silice/tree/master/learn-silice#f...
- https://github.com/sylefeb/silixel
(edit: formatting)
I'm the author of 'q5k' (Quake viewer in 5K LUTs) and so I wanted to say Hi to my fellow Quake-on-FPGA enthusiasts. Thanks for the mention, and looking forward to the next steps of your projects!
PS: Q5k is of course much, much slower (runs on a small $10 ice40 up5k FPGA), and only a viewer. The renderer is custom using fixed-point only. Unlikely I'll be ever able to run the full game at any decent speed, but I'm surely going to try :) For anyone interested, here's the repo of q5k and doomchip-onice: https://github.com/sylefeb/tinygpus
Lua is used as a pre-processor language. This is quite powerful, for instance to automatically generate code, read data into BRAMs (for init), for example RISCV compiled code or DooM wad data (!!). This is used in most projects, see for instance 'pipeline_sort', 'ice-v' or 'doomchip' (a bit extreme there). All lines starting with $$ are pre-processor code, and inserts such as $N$ concatenate the Lua generated N in the Silice code. You can for instance write a for loop with Lua that will duplicate Silice code to e.g. generate a sorting network.
I also try to build an environment around Silice so that one can easily get started and enjoy testing things, experimenting with relatively advanced projects that are also (for several) explained in details. (The build system relies upon many great projects: yosys, nextpnr, edalize, openfpgaloader, verilator, icarus, etc.)
But this is a very subjective thing ; I absolutely understand that others may not like it or feel it is not necessary, being already expert at other tools. Also, I would never argue that one should use Silice instead of X. Take a look at the repo, checkout a few projects (I recommend 'vga_demo', 'terrain', 'ice-v', 'pipeline_sort' and, for pushing beyond reasonable, 'doomchip'). If you see something you might like, perhaps try making a simple design, see if that is a good tool for you.
Yes, exactly! Silice is only a thin abstraction layer over Verilog with a few syntax conveniences (fsms, pipelines, BRAMs, groups, interfaces, please see README ).
You can design in Silice in a way similar to Verilog ( with more comfort -- well I hope :) ) and choose to use some of its more advanced helpers such as building FSMs with explicit control flow constructs (while/break/subroutines).
Silice only does a few optimizations/transformations and they are very predictable (most rules are already documented), so you can still reason about your design directly in terms of flip-flops, states, multiplexers, etc. In this way it is much simpler compared to what I understand an HLS to be (these are capable of remarkable optimizations). I am trying to strike a balance between comfort of design and remaining very close to the hardware.
Silice generates Verilog, and I have to say it is not pretty -- I am not expecting anyone to directly edit the output. However Silice easily interops with Verilog: one can directly reuse existing modules and access vendor specific primitives -- also Silice generated Verilog could be easily integrated in Verilog projects, but I yet have to make this easier.
As I said in another thread (https://news.ycombinator.com/item?id=27575174) the spirit in which I am developing Silice is "I hope you'll find it useful" ; there are many options out there and I think it is great to have various tools for various problems and various styles.
If you have some pointers on this I'd like to learn more. In particular, I'd like Silice to be under a GPL style license (so that everyone benefits from improvements), but also to ensure that what is produced with Silice (designs coming in/out of it) is not 'contaminated' by the license.
There's a related issue in Silice github on this: https://github.com/sylefeb/Silice/issues/106
In many ways Silice is very simple. Just a thin abstraction layer with helpful syntax helpers (groups, interfaces, pipelines, fsm), automating some checks and performing simple optimizations (e.g. flip-flop pruning). But please see the README for all details.
The spirit in which I am developing Silice is "I hope you'll find it useful" and absolutely not "this will be the definitive HDL". First, I am surely not qualified enough to imagine achieving such a goal, and second I am a big believer in having various tools for various problems and various styles.
So I hope you'll find it useful :) I am taking great care in providing a build system to make it easy to get started both in simulation and real FPGA hardware. This relies on many other great projects: yosys, nextpnr, edalize, openfpgaloader, verilator, icarus, ...
Also, Silice comes with fun examples! https://github.com/sylefeb/Silice/tree/master/projects
My initial objective was more about creating some non-trivial hardware using the language I am working on, as well as learning how to implement and optimize algorithms in the context of FPGA. Due to my background in graphics / game programming, revisiting the Doom renderer was a perfect test case! Now that I have this first prototype I want to optimize and fine tune it some more, before adding too many features -- especially as this is meant to serve as a tutorial/example for the language.
Also, I am no language expert, and not an FPGA expert either (I have been learning for ~ 1 year). I shape this for my own use, hopping it will be useful for others, but I wouldn't pretend nor expect to be achieving something particularly new or interesting at large. Nevertheless, I am using it to build increasingly more complex hardware, the doom-chip being the most advanced so far. Every time the language is extended and fine tuned, so it is rooted in practice.
=> The following is an excerpt from the being-written documentation introduction:
My goal is to make it possible to write algorithms for FPGAs in the same way we write them for processors: defining sequences of operations, subroutines that can be called, and using control flow statements such as while/break. At the same time, the language remains low level. Everything an algorithm does is precisely timed, you can fully exploit the parallelism and niceties of FPGA architectures, clock domains are exposed.
My approach is reminiscent of high performance programming in the late 90s (in the demo scene in particular): the then considered high-level C language was commonly interfaced with time-critical ASM routines. This enabled a best-of-both-worlds situation, with C being used for the overall program flow and ASM used only on carefully optimized hardware dependent routines.
The language aims to do the same, providing a thin programmer friendly layer on top of Verilog, while allowing to call low level Verilog modules whenever needed. It favors and exposes parallelism, so as to fully utilize the FPGA architecture.
The main design principles are: - Prioritize combinational over sequential execution. Parallelism comes first! - Clearly defined rules regarding clock cycle consumption. - Explicit clock domains and reset signals. - Inter-operates easily with Verilog, allowing to import and reuse existing modules. - Familiar C-like syntax (but this is not C! different constructs for parallelism, pipelining, etc.). - Powerful LUA-based pre-processor.
Magazines would bundle floppies (and then CDs) full of levels, with new textures and recorded games. Total conversions were made. Tools appeared to directly manipulate the executable and achieve various effects. As far as I remember no other game before had clustered such a large and active community around it? (which is not to say that no other great and amazing games existed before, so many gems lie in the past!)
And then there was the networked play. I spent an afternoon with a friend soldering a cable to play 'null-modem', and we got it working around ~6pm. At 5am the next day we were still playing, me on a luxurious 486 DX2-66, my friend in a tiny window on a 386 DX-33Mhz, both with red eyes. This was an experience like quite no other at the time.
The gameplay was simplistic but huge fun. The immersion was intense. The tech was stellar. But I am obviously biased by nostalgia ;)
Adding a keyboard/joystick input is high on my todo. In terms of moving around this really should be just a question of wiring it to the board: the renderer takes a generic x,y,z + angle viewpoint as did the original engine. However, this also means checking for collisions with the BSP scene which is fun to implement (a nice trick in a BSP is to shift the line equations and check with a point as opposed to checking with a disc of some radius).
Side note: I instrumented chocolate-doom (fantastic port) to output the path shown in the video. Initially I was loading a demo lump, but I realized that these are only the inputs and could not easily reproduce the exact way the game answers them (for example, progressive acceleration and of course collisions).
Next up on my list are correct blinking lights, working doors/lifts and sprites (things + enemies). But I also want to optimize it, and to release the language I used to make this. So quite a huge todo; we'll see how it goes. In any case all of that will be made available so everyone can join the fun!
I love GPUs, I spent many year working with them (still do!) and these are beautiful pieces of hardware and engineering (as modern CPUs are). They have evolved beyond our craziest dreams since the NVidia register combiners (https://www.khronos.org/registry/OpenGL/extensions/NV/NV_reg...). The performance we get nowadays is absolutely mind-boggling (I often think we don't fully realize how powerful they actually are).
Can we dream of some sort of mixed platform, where we could 'burn-in' very specific functions into FPGA type hardware that would seamlessly interact with our modern GPUs/CPUs? Is it already happening?
I agree the state index can be seen as an instruction counter, albeit into very specialized instructions: there are no two same instructions in a given module, each is uniquely implementing a precise subpart of the algorithm. Also the states decide the flow and select the next state, there is no list of instructions you could program or re-arrange. So I wanted to capture this idea that the algorithm is completely embedded into the circuit itself, which is not capable of doing anything else.
There is definitely a very interesting trade-off between a general instruction set and an extremely specialized state machine like here - combining both seems promising?