Assembler on Raspberry Pi
29 points by cpp_frog 1 year ago | 17 comments- neonate 1 year ago
- ksaj 1 year agoI did some experimenting with RPi assembler a handful of years back, since I used to do a lot of x86 assembler throughout the 90's. If you're interested, here are 6 completely different ways to print Hello World in Assembler for the Raspberry Pi.
https://github.com/ksaj/helloworld
I kept the code as close to each other in format and style as possible, so comparisons are easier to make. I don't really know the benefits and drawbacks to each method, but they are there and available, so I sleuthed them out and got them working.
- zokier 1 year ago> Hello World bypassing clib altogether, and talking direcly to the hardware. Apparently this is a no-no, even if it is theoretically more efficient. The bare-metal and OS dev folk are pretty much limited to using this method until their kernel boots and provides other methods, like those covered already.
This doesn't seem quite right; the code doesn't use libc, but it talks to kernel and not directly to hardware. On Linux I don't think direct syscalls are in any way "no-no". But most importantly it still doesn't work on bare-metal; indeed, the hardware has no concept of stdout
- ksaj 1 year ago"Software Interrupt (SWI) functions are functions that run in Supervisor Mode of ARM7™ and ARM9™ core and are interrupt protected."
also
"This means that the processor state changes to ARM, the processor mode changes to Supervisor, the CPSR is saved to the Supervisor Mode SPSR, and execution branches to the SWI vector"
I'll have to go into that further. I was under the impression it was similar to the x86 OUT opcode. So is it more akin to a "direct syscall" then?
- brontitall 1 year agoI wrote a longer answer in response to your other comment. It has a lot of explanation that I see from this comment is likely not needed for you. I’m pasting it here, anyway. I’m no expert in ARM assembler but it appears that SWI 0, later renamed SVC[1], is how you make system calls in ARM Linux[2]. That would make it equivalent to x86 syscall. In other words, it’s the underlying mechanism that libc uses to ask the kernel to output some data. In this case you are calling the write[3] system call (selected by r7=4) with the arguments (r0:fd=1 - file descriptor 1 – i.e. stdout, r1:buf - the address of the data to write, r2:count=14). The kernel then does whatever is necessary to accomplish that write. It could be talking to the video core to update the text console or the contents of a window. It could be passing it to its lower networking layers for sending over an existing network connection for an ssh connection.
It’s pretty fundamental to the Linux kernel that you can’t access any hardware directly unless things have been set up specially to allow it in a limited way. If you really want to deal directly with the hardware, you either have to convince the kernel to allow you to, or run without an operating system. In that latter case, it’s on you to drive all of the hardware. And there’s actually quite a lot of hardware involved in getting stuff displayed on a raspberry pi screen.
[1]: https://developer.arm.com/documentation/qrc0001/latest/ [2]: https://man7.org/linux/man-pages/man2/syscall.2.html [3]: https://man7.org/linux/man-pages/man2/write.2.html
- brontitall 1 year ago
- ksaj 1 year ago
- becurious 1 year agoDirect to the hardware would be initializing the frame buffer and writing there. Which means that you need to have all the glyphs and then look them up and write them into the frame buffer.
This is what we used to do with 8 bit computers that didn’t have a hardware text mode. You might be able to look up the bitmaps in the ROM, otherwise it’s time to define them all yourself.
Using a direct system call would be like calling a ROM routine or an OS routine to print characters. You’d either call the routine or invoke a software interrupt.
- ksaj 1 year agoCheck my reply earlier in the thread. I was working under the assumption that SWI is akin to x86's OUT opcode. Maybe you can decode the quoted stuff and set my brain straight.
- becurious 1 year agoSWI is just software interrupt. Gets trapped by supervisor mode. Then the registers can be decoded by the kernel to implement the correct syscall. Old school real mode x86 equivalent would be an INT instruction.
If you want to do straight to the hardware bare metal then you need to do something like this (https://www.rpi4os.com/part5-framebuffer/) but you’re going to have to do all the other system init work that a modern system needs. Old computers were simpler!
- becurious 1 year ago
- ksaj 1 year ago
- zokier 1 year ago
- markx2 1 year agohttps://www.chibiakumas.com/z80/AmstradCPC.php
Oh wow, memories!
Had an Amstrad CPC6128 in the mid-80s and for the life of me I just could not 'get' BASIC. "Syntax error" in everything, even those multi-page type-in games that Amstrad Action would print each month.
Then I discovered the MAXAM ROM - along with Protext. That, a copy of the CPC Firmware Guide, and I was away.
BASIC stumped me but the Z80 language just clicked.
Loved writing code, learnt the importance of backups, learned how to find cheats in games and so much more. Good times.
- self_awareness 1 year ago
- unwind 1 year agoWait what there is no integer division instruction? That sounds very weird and [1] disagrees by describing SDIV and UDIV. What?
[1]: https://developer.arm.com/documentation/den0024/a/The-A64-in...
- molticrystal 1 year ago>hw-rpi3-5 Hello World bypassing clib altogether, and talking direcly to the hardware.
>Apparently this is a no-no, even if it is theoretically more efficient. The bare-metal and OS dev folk are pretty much limited to using this method
This seems to be just a call into the linux kernel, not bare metal, essentially what the clib does itself. You have to do this to do functions the kernel supports but haven't been ported to clib yet.mov r7, #4 /\* raw system call for write */ swi #0 /* print without using clib \*/
I haven't really looked deep into it but a google search came up with this for bare metal text printing https://github.com/bztsrc/raspi3-tutorial/tree/master/0A_pcs...
- ksaj 1 year agoThanks. I will be updating the text shortly.
"You have to do this to do functions the kernel supports but haven't been ported to clib yet."
This is insightful. I'll reflect it in my updated text.
- molticrystal 1 year agoI meant the comment you responded to for a different thread, but yes, there is a strong mapping between the kernel of an OS and the preferred C library of that OS, because what is the point of exposing functionality to programs in userspace, like more efficient methods, if you have to crack open kernel docs to figure out how to use it, instead of a nice wrapper in your C library. And both the kernel people and the clib people want you to have access to better methods.
But as their goals and timelines are different, they are out sync, which comes into play not only in the new functionality not being included, but variations of existing functionality where the function has additional flags or parameters that the clib function hasn't added. For example, you'll often see this in areas involving threading, starting processes, and sockets. Luckily for most people you'll often find a fork of the clib or just a 3rd party library that wraps the functionality, but if you are on cutting edge or using a feature that never really caught on because its applicability is very niche, you'll have to go back to syscalls.
- molticrystal 1 year ago
- ksaj 1 year ago
- codewritinfool 1 year agoMinor nit (for me, at least): An assembler is a tool. Assembly is a language.
Though not assembly language, I think that www.ultibo.org is a cool embedded development environment for the Pi.