I've also recently discovered the joy of system level programming. I've gone through a few iterations of writing a (incomplete) kernel from scratch using different languages. I started with a 32-bit kernel in C and got as far as preemptive multitasking.
Then I decided to try Nim, I found it very ergonomic and lets you write compact code that expresses the main logic without too much syntax noise. But I got blocked by some issues making it work for a UEFI target.
Then I tried Zig and got as far as parsing ACPI tables and writing an AML bytecode parser. Zig is nice and I like its optionals support and error handling approach. But I was put off by its noisy syntax (e.g. !?*[*]u8 to represent an error union of an optional pointer to a many-pointer of uint8). Also having to prepare and weave allocoators throughout most of the code that needs to dynamically allocate (which is most of the code) gets in the way of the main logic. Even little things like string concatenation or formatting becomes a chore. In the end I realized that Zig is not for me.
So I got back to Nim and resolved the issues that were blocking me. I'm now on my journey to write a complete kernel in Nim (so far I have access to UEFI services and ACPI table parsing and on my way to get interrups working). The code is pleasant to write and read. Also the language and the stdlib documentation is great (Zig's stdlib documentation is almost non-existent.)
Overall, I found that systems programming is very satisfying, and you can depend on specs that rarely change (some are over 20 and 30 years old and still work the same way today) and is quite a welcome change from web dev where it depends on tech de jour.
I wasn't ready to share it yet, but here it goes[1]. It's at a very early stage, but should give you an idea of how to get things up and running under Nim.
I didn't avoid malloc. I provided a simple bump pointer based heap to get things going. Later I'll have to separate things into a UEFI bootloader and a proper kernel image, each with its own allocator (the bootloader will use UEFI memory allocation services, and the kernel will have its own heap).
That's somewhat similar to what I'm doing with Miniforth [0]. Programming in a minimal environment is fun. I don't have a separate machine, so I'm booting my main laptop from a thumbdrive. The difference in boot time is staggering – after BIOS loads the boot sector, everything else is instant. This is instrumental to my strategy for tricking myself into working on the project – normally, I'm very prone to going off into a research rabbit hole after taking a look at the wrong browser tab. So, instead, I make sure to power off my machine in the evenings. That way, booting into miniforth becomes the option with less friction (:
Unfortunately, this does not work for writing the blog about the project. Hopefully this will change soon, once I write an editor and filesystem...
Lately, I've been reliving my youth of writing 6502 assembly language, inspired in part by one of Ben Eater's videos[1], and with the aid of Easy 6502[2].
I think that programming in assembly language is compelling because it is "rightsized" for the human brain. You spend a lot of time solving small, manageable puzzles about the best way to do achieve small victories like trying to squeeze every last cycle or byte out of some small section of code. And then you sit back and laugh because after all that struggle you managed to compute something that would take an insignificant amount of effort to do in a high level language. But it works on this very limited device, and that's a thrill.
If you want a more modern microcontroller that can actually be used to make things, take a look at the 8 bit STM8 series. They are widely used (you may have a few already, toasters, rice cooker, car etc). They definitely have that 6502 flavor, although even closer to being MC6800 improved, (eg 16 bit index registers), plus a good set of timers, ADCs, UARTs, SPI, I2C etc.
Official "Discovery boards" from ST include a programmer and debug connection for under $10, and cheap dev boards are plentiful. Open source C compiler SDCC, and free tools from ST.
There is also a very good Forth [0]. Even if Forth is not your thing the site has a lot of good information on STM8.
I really like when someone has such dedication to distractionless work. Reminds me of simpler times, when people used computers for useful things, with a local game or two as an only medium of entertainment.
Now we have too many distracting mediums that are only a click away.
Internet has made many things easier, but the real cost of it is yet to be determined.
So, firstly, I’m amazed anyone can do that in bed and then sleep properly. I’d be dreaming in assembly all night.
When the author talked about reading the entire GNU Screen manual I did think “this sounds like stressful overkill” for a personal project, but I see their point about focusing on process rather than goal.
Does it ever really matter than personal projects don’t get finished?
Same boat. Exercising my brain before sleep basically means I'll sleep very late because I just have to figure it out or figure out that I can't figure it out in a few hours. The author seems to possess some super human power to cool down whenever he wants, or he is super good with assembly.
I'm thinking, maybe the trick is to pick an exercise that can be easily decomposed into steps, each of them requires very little time and energy.
For example, translating one assembly to another with the same architecture might fit the description because most of the time you are just doing "translation". Of course I'm not an assembly professional so I might be underestimating the difficulty here.
Another good example is carpentry. As long as you finish step X you can leave it there. There is no need to burn candles to finish all steps at once.
A bad example is algorithm design. Unless it's second nature to you, it's really difficult to decompose it into steps (because maybe they are wrong steps), and even if you can, picking up from where you left off last night might actually be more difficult than starting over from the beginning.
I’ve tried this and it sort of works, but what happens is that I get excited by the sense of achievement and want to do more, and/or get wrapped up in thinking through the next steps.
I also absolutely do not allow myself to learn new things before going to sleep otherwise I will be thinking and dreaming about it in a kind of sick way. This is specially harmful on week days where it disrupts my sleep. Sleep is essential for my well being and professional ability.
Because my mind will be racing before I go to sleep, making it harder to get to sleep, and then my dreams are really dull but repetitive and I wake up mentally frazzled and worn out. Almost as if I’ve mentally computed a long loop for hours.
The other evening I did a small amount of work on a compiler I’m making and for ages all I could think was “compilers! So cool! Making those basic blocks! Yeah!”.
It would be cool if I had a dream where I intuitively understood whatever I was designing, but my dreams aren’t that insightful…
If hand-written assembly becomes a fashion trend of 2022 (must say I'm tempted) - are there any good targets for optimization in popular free software packages that anybody here can think of? Filters in GIMP, effects in Audacity, etc?
Interesting question, but I think you'll be hard pressed to find many large, popular projects still using large amounts of load-bearing assembly in the-year-of-our-lord-2022 since compilers have gotten very good and we still really care about portability since aarch32, aarch64, x86-64, and (less to) x86 are all reasonable targets that tons of people use.
I'm not sure how into systems programming you are, but there is globs of interesting assembly worth optimizing in various kernels. Interrupt routines, optimized memcpy, filesystem encryption, etc. are all great places where a small speed boost will have very large impacts on the overall platform performance.
I recently started manually writing assembly with focus AVX2 (a flavor of Intel SIMD extensions). The rationale is that these are complex enough that compilers do not always notice the opportunity to use them, so my ultimate goal is to apply this is to find a non-artificial problem where I could beat a compiler :-)
I confirm that its one of the most satisfactory ways to add some numbers using a modern computer.
I found surprisingly little material about "how to program AVX/AVX2". That said here's what I used so far:
* Intel AVX Programming Reference [0] - comprehensive but not very useful as "where do I even start"
* Godbolt[1] to look at code samples produced by compilers. This is good to see how the instructions work together.
* A random discussion that has *some* concepts behind the YMM registers[2]
* Stack Overflow, for example [3]
I've been trying to explore programming bootloaders a bit. I've got an unorganized collection of resources and a bunch of test bootloader programs that are not documented.
I haven't figured out how to get gdb hooked so I'm just debugging with a print integer routine. That's annoying.
And writing to and reading from the bios video service (int 10h) in my text editor bootloader is not the most fun. Randomly characters get overridden and it could be my code or register state I haven't reset but it's pretty hard to get right and understand the bios APIs.
I'm getting ready to give up than write anything about my bootloaders since their behavior is not always deterministic in more complex programs (boot4.asm is the complex text editor and sometimes when hitting backspace on the last column in a line the cursor sometimes freaks out trying to find the end of the previous line.)
"Also, though I did install Lynx, this is not a great machine for modern Web surfing (except for ratfactor.com, of course). So it's a pretty distraction-free device."
As an owner of one these ASUS EeePC netbooks I used links (a different text-only browser) in VGA textmode in NetBSD for many years. For the small screen size, the terminal font is easy on the eyes. Lynx is one of the worst text-only browsers, IMHO. For me, staying in textmode prevents distraction. However I am reading from the www in textmode all the time. A large, complex, Javascript-enabled, advertising-sponsored, graphical browser is not necessary. No idea what "modern Web surfing" means but it does not sound like it is worth the time if all it produces is distraction.
> Lynx is one of the worst text-only browsers, IMHO.
What are you using then? I didn't like the "bloatedness" of the modern web. So I often use browser "reader mode". But I would happily try something different.
Porting the output generator from my toy compiler into AT&T syntax to only depend on GAS back when its Intel support still wasn't that good was a lesson in never doing it again.
I honestly even buy the "convention" argument. Damn near every other assembly language uses <op> <dst> <src> pattern and so trying to read at&t always feels like pig latin
I have one of those old netbooks and was looking for a lightweight linux distro to install in it, is Alpine the best one for this? Any other recommendation?
Then I decided to try Nim, I found it very ergonomic and lets you write compact code that expresses the main logic without too much syntax noise. But I got blocked by some issues making it work for a UEFI target.
Then I tried Zig and got as far as parsing ACPI tables and writing an AML bytecode parser. Zig is nice and I like its optionals support and error handling approach. But I was put off by its noisy syntax (e.g. !?*[*]u8 to represent an error union of an optional pointer to a many-pointer of uint8). Also having to prepare and weave allocoators throughout most of the code that needs to dynamically allocate (which is most of the code) gets in the way of the main logic. Even little things like string concatenation or formatting becomes a chore. In the end I realized that Zig is not for me.
So I got back to Nim and resolved the issues that were blocking me. I'm now on my journey to write a complete kernel in Nim (so far I have access to UEFI services and ACPI table parsing and on my way to get interrups working). The code is pleasant to write and read. Also the language and the stdlib documentation is great (Zig's stdlib documentation is almost non-existent.)
Overall, I found that systems programming is very satisfying, and you can depend on specs that rarely change (some are over 20 and 30 years old and still work the same way today) and is quite a welcome change from web dev where it depends on tech de jour.
Edit: Here are the github repo links:
- C kernel: https://github.com/khaledh/bitflow
- Zig "kernel": https://github.com/khaledh/axiom-zig
- Nim "kernel": https://github.com/khaledh/axiom