I think one great way to do this is to get a Commodore 64 emulator (or Atari 2600 etc) and start writing and learning 6502 assy. Arguably its one of the last instruction sets that was designed with humans writing code in assembly (and not in some higher level language) making it excellent learning language. You can readily run your code in emulators and for not too much $$$ you can pick a real hardware from EBay to really run it on HW.
And once You think you’ve run hw to its limits there are plentiful demos and examples around to blow your mind watching what people have been able to do with these machines (often in obscure ways).
Commodore 64, sure, but I wouldn't recommend the Atari 2600 for beginners! I wrote a small game for the 2600 years ago, and it's a tricky little machine. It doesn't even have a video frame buffer, so you have to do things on the fly, depending on which line of the screen is being beamed (think of old-school CRTs).
I've always been skeptical of using retro machines to learn low-level programming.
While the processors are simple, making non-trivial programs is hard, because the machines as a whole have lot of limitations, making programming very intricate, compared to more modern systems (say, 16-bit 80x86, but I guess even Amiga and so on).
If the target it challenge for the sake of challenge, then nothing makes those machines special, I mean, one can code directly in machine code if that's the intention :-)
> And once You think you’ve run hw to its limits there are plentiful demos and examples around to blow your mind watching what people have been able to do with these machines (often in obscure ways).
What blew my mind was using a modern C++ compiler to build optimized software for that old hardware. Here's an example with the Commodore 64 [0].
I learned mips in a college class and quite enjoyed it. How does mips compare to C64 asm? I don't know any other asm besides mips (unless zachtronics games count) and but have been playing around with the idea of writing a simple asm OS. Would C64 asm be a good choice? I've also heard that m68k asm is nice. How do the three compare?
When the CPU starts, it will start reading instructions from a hard-coded address on the memory bus / EPROM somewhere, right? How can I directly control these bytes?
I don't want some proprietary firmware sit between me and the CPU.
If it's not possible on hardware because "secure boot", or whatever, this should at least be possible in emulators like QEMU.
Does anyone know how to do that? ... or clear up my misconceptions? :)
A physical machine will still, despite everything, start executing at FFFF:0000 in "real mode", and the code run there will be found in a physical EEPROM. Some of these are socketed (although this is less common these days). So you can get in there and fiddle with the pre-boot code.
There is no way round the Management Engine, a source of distress to some. Oh, and you won't have any DRAM until you've run the DRAM training and turned that on, the early BIOS gets to use the cache as a scratchpad instead. See https://blog.asset-intertech.com/test_data_out/2014/11/memor...
If you like bare metal work with decent processing power ARM is probably the place to start.
Below UEFI is the BIOS, or the firmware formerly known as the BIOS. There is a project to make an open source firmware for PCs: https://www.coreboot.org. It works on a selection of newish motherboards.
You can't really start completely from scratch in an understandable way on Intel platforms, and it's iffy on ARM. Because setting up the DRAM requires some insane magic, where it doesn't really help if you can see the source.
> I don't want some proprietary firmware sit between me and the CPU.
No, you do.
A significant part of what that firmware does is initializing low-level hardware, like the system's memory controller. Replicating that is probably well beyond your abilities.
Go check out the Coreboot project. They're about as low-level and bare metal as you can get, because Coreboot is not running on the board firmware, it is the board firmware. And as an open source project, they document all the various things they have to do in order to initialize all the hardware on a board and have it ready to be used.
You are generally correct in your assumption: that once the CPU comes out of reset, it will reach for a particular memory address to begin execution. Some will directly begin execution from a fixed address. A sibling pjc50 comment mentions, on x86, the CPU will be in 16-bit real-mode and begin fetching instructions from FFFF:0000. Other architectures, work slightly differently. Motorola 68k fetch the first 4 bytes from 0x00000000, loads them into the program counter register, and then jumps there to begin execution.
As you saw, the child of a pjc50's comment explains how to pass your code directly to the beginning of the CPU's execution in QEMU. If you want to do this with actual metal, various classic chips of yore (z80, 6502, 68k, etc) and their documentation are relatively easy to get. A nice thing about those older CPUs, is that their memory interfaces are rather simple compared to today. You can wire up a very basic system with the CPU, an EPROM, an SRAM chip, and maybe a couple other chips as glue logic, all on a basic breadboard. And then you really can control those first bytes of executed code, on actual metal.
Not exactly bare metal when you've got UEFI in there.
In the embedded world, Bare Metal means you control the first byte executed by the CPU when it comes out of POST, and aren't using any kind of operating system or proxy loader in between. But it gets kinda fuzzy, because RToS is still "bare metal" and you have full access to the source-code.
If you want to go down a different rabbit hole than being "bare-metal" while still being in UEFI, take a look at EFI Byte Code: it's a strange and arcane little virtual machine that you can use to write cross-platform UEFI drivers. Here's a simple emulator for it: https://github.com/yabits/ebcvm
I recommend anyone just starting with bare-metal assembly to get an STM32F0 board and write assembly programs for it. I'm just gonna plug my super small toy RTOS I wrote for Cortex-M0 a while ago.
Just an aside, but it always felt weird to me that we call is bare-metal while the actual code runs on mostly semiconductors.
I am very glad that in my bachelor program our microcontrollers class actually made us hand enter hex codes in a kit. It got tedious after a while (maybe it should have been for only a few weeks not the whole semester), but it gave me a weird sense of being one with the machine. And it has as awesome ice breaker when talking with older programmers. For some of them I am the only one of my age that they have met who has ever done this. Another thing is it helped me sort of see the flow of it and encouraged optimization.
(I don't want to give too much credit to my college, they did it not as some great pedagogical trick but to save money and laziness)
Bare metal comes from mainframe days. The largest systems like IBM 360-67 and others were called "Big Iron" - see https://www.ibm.com/ibm/history/ibm100/us/en/icons/system360... for NASA's moonshot-era Big Iron. You could run programs on OS/360 or you could, if daring, run code directly on the machine, on the "Bare Metal". It's quite common to run 1-card programs on the Computer History Museum's IBM 1401 --- which was not really considered 'Big Iron' at the time, although today we call it a 'Mainframe' https://computerhistory.org/exhibits/ibm1401/
I think it might come from auto body shop terminology. We would remove layers of paint or rust and get down to the "bare metal" for prep work. That "down to the bare metal" phrase was very commonly used.
That is to say "no layers" or "right on the substrate".
My first actual programming class was on an Intel 8085 kit, and I have to say that hand-assembling on pre-printed carbon sheets was pretty cool. It has served me well in my career to have started at that level.
We also pogrammed the 8085 machine very recently(2015). It was a very weird feeling realising all the myriad of abstactions come down to basic load/store/arithmetic/logical instructions. Had fun implementing squaring a number whose result wouldn't fit in a register.
Hasn't always been semiconductors... or electronics at all, for that matter. That just happens to be the current majority physical implementation, where metal is a little scarcer than it used to be.
A couple of years ago, I was learning PDP-11 assembly on 2.11 BSD and enjoying it, but then the old textbook got to the point of system calls. I couldn't get anything working properly, so eventually I found something else to do. I did very much like it though.
Also, TIS-100 from Zachtronics (the assembly language game you never asked for!) I think made assembly type programming less intimidating.
debug hn.com
a 100
mov dx, 200
mov ah, 9
int 21
mov ax, 4c00
int 21
a 200
db "Hello, World$"
w 300
q
Replace 100 with 0 and write it to the first sector of a disk and you had a bootable program (BIOS interrupts only, of course).
Edit: Geezus. It's just an example of how accessible getting something running in assembly language was compared to all the qemu, UEFI stuff in the article.
Does anyone know if qemu and OVMF can be made to work in plain text mode? I just tried but qemu wants GTK by default, and when I pass -curses I get a message that the screen is in 640 x 480 graphics mode.
Is UEFI really that complex that it doesnt allow for plain console access?
I always wanted to do this stuff, but classes just never taught it. I think some of the ECE students got some classes which taught some assembly, but not us lowly CS people.
Why are assembly related topics so popular on Hacker News? I don't see pursuit of this topic happening in my anecdata of programmers I interact with in day to day life.
[+] [-] rixrax|6 years ago|reply
And once You think you’ve run hw to its limits there are plentiful demos and examples around to blow your mind watching what people have been able to do with these machines (often in obscure ways).
[+] [-] mksaunders|6 years ago|reply
Indeed, a whole book was written about it: https://en.wikipedia.org/wiki/Racing_the_Beam
The 2600 is fascinating and fun to code for, but for asm newbies I'd recommend the C64 or NES...
[+] [-] pizza234|6 years ago|reply
While the processors are simple, making non-trivial programs is hard, because the machines as a whole have lot of limitations, making programming very intricate, compared to more modern systems (say, 16-bit 80x86, but I guess even Amiga and so on).
If the target it challenge for the sake of challenge, then nothing makes those machines special, I mean, one can code directly in machine code if that's the intention :-)
[+] [-] inetknght|6 years ago|reply
What blew my mind was using a modern C++ compiler to build optimized software for that old hardware. Here's an example with the Commodore 64 [0].
[0]: https://www.youtube.com/watch?v=zBkNBP00wJE
[+] [-] akkartik|6 years ago|reply
[+] [-] smabie|6 years ago|reply
[+] [-] pjmlp|6 years ago|reply
[+] [-] heinrichhartman|6 years ago|reply
When the CPU starts, it will start reading instructions from a hard-coded address on the memory bus / EPROM somewhere, right? How can I directly control these bytes?
I don't want some proprietary firmware sit between me and the CPU.
If it's not possible on hardware because "secure boot", or whatever, this should at least be possible in emulators like QEMU.
Does anyone know how to do that? ... or clear up my misconceptions? :)
[+] [-] pjc50|6 years ago|reply
A physical machine will still, despite everything, start executing at FFFF:0000 in "real mode", and the code run there will be found in a physical EEPROM. Some of these are socketed (although this is less common these days). So you can get in there and fiddle with the pre-boot code.
See https://www.drdobbs.com/parallel/booting-an-intel-architectu...
There is no way round the Management Engine, a source of distress to some. Oh, and you won't have any DRAM until you've run the DRAM training and turned that on, the early BIOS gets to use the cache as a scratchpad instead. See https://blog.asset-intertech.com/test_data_out/2014/11/memor...
If you like bare metal work with decent processing power ARM is probably the place to start.
[+] [-] kryptiskt|6 years ago|reply
You can't really start completely from scratch in an understandable way on Intel platforms, and it's iffy on ARM. Because setting up the DRAM requires some insane magic, where it doesn't really help if you can see the source.
[+] [-] duskwuff|6 years ago|reply
No, you do.
A significant part of what that firmware does is initializing low-level hardware, like the system's memory controller. Replicating that is probably well beyond your abilities.
[+] [-] guerby|6 years ago|reply
https://www.sifive.com/blog/an-open-source-release-of-the-fr...
[+] [-] stefan_|6 years ago|reply
If you really want to understand and control a processor when it boots from nothing, you should look into a FPGA RISC-V development board.
[+] [-] korethr|6 years ago|reply
You are generally correct in your assumption: that once the CPU comes out of reset, it will reach for a particular memory address to begin execution. Some will directly begin execution from a fixed address. A sibling pjc50 comment mentions, on x86, the CPU will be in 16-bit real-mode and begin fetching instructions from FFFF:0000. Other architectures, work slightly differently. Motorola 68k fetch the first 4 bytes from 0x00000000, loads them into the program counter register, and then jumps there to begin execution.
As you saw, the child of a pjc50's comment explains how to pass your code directly to the beginning of the CPU's execution in QEMU. If you want to do this with actual metal, various classic chips of yore (z80, 6502, 68k, etc) and their documentation are relatively easy to get. A nice thing about those older CPUs, is that their memory interfaces are rather simple compared to today. You can wire up a very basic system with the CPU, an EPROM, an SRAM chip, and maybe a couple other chips as glue logic, all on a basic breadboard. And then you really can control those first bytes of executed code, on actual metal.
[+] [-] mkup|6 years ago|reply
[+] [-] Wowfunhappy|6 years ago|reply
[+] [-] ngneer|6 years ago|reply
[+] [-] unknown|6 years ago|reply
[deleted]
[+] [-] 0xff00ffee|6 years ago|reply
In the embedded world, Bare Metal means you control the first byte executed by the CPU when it comes out of POST, and aren't using any kind of operating system or proxy loader in between. But it gets kinda fuzzy, because RToS is still "bare metal" and you have full access to the source-code.
[+] [-] waynecochran|6 years ago|reply
[+] [-] saagarjha|6 years ago|reply
[+] [-] kahlonel|6 years ago|reply
https://github.com/kahlonel/rt0s
[+] [-] 0xff00ffee|6 years ago|reply
I have still yet to really need an RTOS, even for BLE.
[+] [-] newswasboring|6 years ago|reply
I am very glad that in my bachelor program our microcontrollers class actually made us hand enter hex codes in a kit. It got tedious after a while (maybe it should have been for only a few weeks not the whole semester), but it gave me a weird sense of being one with the machine. And it has as awesome ice breaker when talking with older programmers. For some of them I am the only one of my age that they have met who has ever done this. Another thing is it helped me sort of see the flow of it and encouraged optimization.
(I don't want to give too much credit to my college, they did it not as some great pedagogical trick but to save money and laziness)
[+] [-] GeorgeTirebiter|6 years ago|reply
[+] [-] tyingq|6 years ago|reply
That is to say "no layers" or "right on the substrate".
Just a guess though.
[+] [-] caspper69|6 years ago|reply
[+] [-] abhishekjha|6 years ago|reply
EDIT: It was 8085 kit, not 8086.
[+] [-] basementcat|6 years ago|reply
https://en.wikipedia.org/wiki/Metallicity
[+] [-] stan_rogers|6 years ago|reply
[+] [-] cptnapalm|6 years ago|reply
Also, TIS-100 from Zachtronics (the assembly language game you never asked for!) I think made assembly type programming less intimidating.
[+] [-] lonelygirl15a|6 years ago|reply
https://eater.net/
[+] [-] fmakunbound|6 years ago|reply
Edit: Geezus. It's just an example of how accessible getting something running in assembly language was compared to all the qemu, UEFI stuff in the article.
[+] [-] 0xff00ffee|6 years ago|reply
A BIOS CALL. :)
Still not bare metal.
:)
(I'm totally gatekeeping for laughs: write your own BIOS you noob!)
[+] [-] gruturo|6 years ago|reply
I'm not sure it would work if you stuck this in a boot sector.
[+] [-] unknown|6 years ago|reply
[deleted]
[+] [-] basementcat|6 years ago|reply
[+] [-] winrid|6 years ago|reply
I have a copy I'd sell, although you can find it for free, legally, online. It's about a thousand pages....
[+] [-] SkyMarshal|6 years ago|reply
[+] [-] greyhair|6 years ago|reply
[+] [-] mlang23|6 years ago|reply
[+] [-] a7b3fa|6 years ago|reply
[+] [-] DoofusOfDeath|6 years ago|reply
[+] [-] liquidify|6 years ago|reply
[+] [-] commandlinefan|6 years ago|reply
[+] [-] ngcc_hk|6 years ago|reply
[+] [-] classified|6 years ago|reply
[+] [-] underthensun|6 years ago|reply
[+] [-] djmips|6 years ago|reply
[+] [-] Koshkin|6 years ago|reply