HN user

sylefeb

69 karma

https://mastodon.online/@sylefeb

Posts0
Comments17
View on HN
No posts found.

Hi there, a while ago I had a ton of fun with the Fomu: https://x.com/sylefeb/status/1571489610647371776

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

This is a fascinating topic, especially when considering how this was achieved back in the days. We now take it for granted, but this was not a simple feature to have in your game in 199x ( x<6 ;) ).

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

Lookup tables are great to produce impressive graphics effects under strict compute limits. I use them in many FPGA projects. On FPGA there is a balance between limited memory (often BRAM) and limited compute, but they can be used to great effect:

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)

Very, very impressive works, both MRISC32 and FuryGPU (which I just learned about, love the idea of a FPGA-retro-GPU that could go in a modern computer!). It's hard to overstate the amount of passion, care and technical expertise that go into such projects.

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

Hi (author) - Thanks! I would like to support FIRRTL very much, I have looked into it a bit in the past and that all looks feasible. It is a rather big feature though, so it will take some time.

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.

Hi (author) - for me Silice brings comfort while designing, simplicity of reuse (groups+interfaces making it easy to assemble components), a syntax that is more to my taste (obviously ;) ) and ease of prototyping with the 'control-flow' FSM style and pipeline constructs. Plus the Lua pre-processor that I enjoy using. All this while staying close to Verilog and being able to inter-operate easily.

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.

Hi, Silice author here -

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.

Hi, Silice author here. I picked the AGPL 3.0 knowing it is on the strict side of the spectrum, but not thinking it would be 'toxic'?

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

Hi, Silice author here. I cannot provide a detailed answer as I am not familiar enough with SystemC. I started Silice as a "quality of life" (in the video game sense) thin layer above Verilog, hoping to obtain something that would be more enjoyable to write with. I'd like this to be true both for getting started with FPGA, but also when describing advanced designs with efficiency concerns in mind (LUT count, max perf, hardware specificity such as DSP blocks, etc.).

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

Unsure, I definitely would like to have fully working environments that can be explored interactively (with proper BSP collisions, doors/lifts, blinking lights etc). Everything is stored in BRAM, unsure the sprites would fit (maybe a few, or at lower res, but I did not look into that yet). When this gets released I hope this will also be reused/expanded.

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.

Happy to - but in full this will be better explained on release on the github README, with code examples.

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.

Doom has had an immediate huge impact in its time ; even before the source code got released the game had a hacker-friendly wibe to it. For instance DEU (the first editor I used) was released in 1994 (https://doom.fandom.com/wiki/Doom_Editing_Utilities). The 'unofficial specs', still invaluable today if you want to hack Doom, were released in 1994: http://www.gamers.org/dhs/helpdocs/dmsp1666.html

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 ;)

True - I only (partially) re-implemented the render loop, and this is far from the complete game. A game is always much more that its core technical components.

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!

(Author here) Thanks - and I agree. That being said this is running 100 MHz on (what I believe is) a relatively low end FPGA? Also my implementation remains simplistic, many things to optimize. But this is a very good and deep question: how can we compare these things? What is the right metric? (FLOPS per watt? err, no, no floating point involved ;) ). I am wondering and this seems quite a difficult/subtle question.

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?

Author here - Thanks! You are absolutely correct there are several state machines (vga, sdram controler, framebuffer, texturing, divider, renderer, etc) and each with an active state index. The renderer is the biggest one with 69 states.

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?