I did some mips at school. Assembly was fun to mess around and get close to the architecture, but I definitely enjoy the benefits of modern languages like return types.
Just subscribed yesterday after finding your other video while searching for a riscv video. And today you upload a riscv one. What a coincidence 😂. I'm really appreciating your video btw.
lmao this was so fast but it saved me from 2 weeks of not figuring out how to progress in my CPE assignment so thank you a million for the help. My prof assumes we know everything
Nicely done and explained. Only thing I personally would change is, that I would use -ld and not -gcc to just make clearer, what is happening. What you actually call is the linker, not the C-Compiler.
@@LowLevelTV I like your use of qemu, so no need to obtain (new) hardware all the time to try something. :) The ESP32-C3 is based upon a RISC-V core, so if you ever want to turn to HW this could be a nice option. I think also the Bouffalo (no typo) BL602/BL604 could be interesting. Finally I'd like to see a scenario where the code segfaults (or similar) and debugging this with jLink so that we put the assembler knowledge to good use (working through the backtrace, fixing the root cause).
The length of the ascii string is 12 IMHO. (was 13 with comma). It is accessing (and printing) one more character, potentially beyond process' address space, I am guessing ELF executable is padded to 512 byte blocks or something. Methinks you could get an exception from kernel if your 13th byte is outside process space.
Wow you’re right. He says “ascii terminated string” at 9:30, but .ascii doesn’t add a null terminator. He’d have to use .asciiz instead. He must have gotten lucky because it didn’t cross a 4k page boundary.
how did you run a risc-v compiled executable on your host machine directly like "./hello" without passing it to qemu-riscv64? Is there some trick that your Linux host is using that I'm not aware of?
@@Naaronn digging old emails from youtube noti in my mail box and found his old comment: > keywords to lurk more: binfmt_misc and qemu user mode very handy to be honest ;)
Looking forward to more videos on RISCV! Can you make a getting started video, with resources for the interested to explore on their own? Also any cheap hardware to run risc programs directly?
Great video! I had a question maybe you could answer. Wouldn't the li instruction be better than using addi when one of the operands is 0? Like, instead of "addi a7, zero, 64", you could just do "li a7, 64".
@@kevinescobedo5633 Even if they produce the same result, they are different instructions. In the physical chip, they would behave according to their specifications, and there could be minor differences, like the number of clock cycles taken or the flags affected.
@@kevinescobedo5633 li is a pseudo instruction that gets converted to "addi a7, x0, 64" behind the scenes. So using it is more concise, but it eventually becomes the same thing so in the end it is just user preference.
Can you drop in what the compiled opcode bytes look like? Curious to see how the compiler outputs the memory address and the opcode bytes... I've done a lot of development in HLL but assembly only on 65C816-class CPUs.
Nice work ! Thankyou. I have a question. I was looking at learning Risc 5 assembly language to enable the programming of one of the ESP32 MCUs. Is it possible to disable absolutely all interrrupts on these chips so that my time sensitive code has no interrupts at run time ? I'm an experienced ASM programmer from the Atmel AVR world.
TOTALLY AWESOME! The coding in RISC V looks quite neat. Could you write THE SAME thing for an ARM 64, like it would compile on a Raspberry Pi4 on Linux? That way it would make it super-easy to learn the differences of the basic assembly infrastructure between those processors. Do the ARM64 people also have a convention with 8 function parameters to start with, or it comes on the stack? Also, you MAY have done this already, and in that case, could you point me to that Hello World ARM Assembly video? I'm such a newbie... THANK YOU SO MUCH. I really like your low-level-learning series, it always comes in small chunks that one can really understand...
Looking forward for more tutorials on RISCV . It would be helpful if you can reduce your pace a bit.(I felt it was a bit fast)(just a friendly suggestion)
Also - I see you used section 3 of the manual for exit(). I haven't really done much Linux syscall programming but shouldn't we check section 2 in this particular case?
The miscounting of string length here highlights the general issue of having to count the string length manually, which is already difficult to get right at 12 bytes. Are there any tools in the compiler or IDE set-up to automate this counting for longer texts etc. ?
No image is needed to run bare-metal programs like this. If you want to run a RISC-V linux then see e.g. wiki.ubuntu.com/RISC-V or if you have Docker installed (on x86 or arm64 machine) try: "docker run --platform linux/riscv64 -it drujensen/riscv-ubuntu bash"
It is when using the Linux compiler, which creates a dynamically-linked executable by default. Doing programs like this -- especially for an embedded board -- you'd probably use riscv64-unknown-elf-gcc instead, which 1) automatically links statically, and 2) uses Newlib instead of glibc (of course this program isn't using the C library at all)
There is valuable information here, especially about how to make Linux calls from within a program, but you are going to learn very little riscV assembly instructions. Just a couple of opcodes.
So let me get this straight. Internal computations are not "meaningful" because they don't talk to the Kernel. 95% of all computations are internal so there is no point in writing applications because most of your application it is not "meaningful".
You had my enthusiastic attention until the syscall section and the realization that you are really just messing around with the Linux kernel using assembly language. I'm glad others enjoy, but, to me, low level assembly programing would not involve a kernel. Making underlying software do the heavy lifting for you is the definition of high level programing.
Nice video! One question, how and where did you find the "qemu-riscv64" command? All I can find in my system is "qemu-system-riscv64". I'm on Arch Linux and I downloaded the following packages: * qemu-system-riscv * riscv64-linux-gnu-gcc Also, how do you even execute the program without using "QEMU" at first? What kind of black magic is this?
Exactly same question here. This is blocking me from following this tutorial, because I kept getting "Exec format error" if I follow the tutorial and simply run "./hello"..
@@godnyx117 You need to install qemu user mode. This worked for me In Fedora: sudo dnf install qemu-user then you run things with qemu-riscv64 ./hello The cool thing is that once I installed qemu-user, I don't even need to type qemu-riscv64 as the loader gets a hook that knows to run RISC-V executables via qemu-riscv64. For Ubuntu, the package is also called qemu-user I think.
@@pierrejacomet8098 Why the FUCK didn't he said it in the video? Unless the package was split after he made the video... Anyways, thanks a lot for the help! It will come very useful in the future! Have an amazing day!
Is there no load immediate instruction to load a number into a register? It's quite a common thing to do, even in this trivial example. It seems a bit clunky that you have to add it to zero. How many cycles does it take?
The assembler provides an `li` mnemonic but it's not a real instruction and for values between -2048 and +2047 it expands to an `addi` instruction. Clock cycles depends on the design of the particular CPU, not the instruction set, but you can expect that no other instruction is faster than `add` and `addi`. On CPUs designed for speed that's going to be 1 clock cycle.
MIPS have abandoned their proprietary ISA(s) and have already announced their first high performance RISC-V CPU. They know how to design hardware, but they couldn't maintain today's expected software ecosystem alone.
Using qemu by the way Why I can't emulate newer cpu models on an old machine Ex: can't emulate 8th gen x86 on 6th gen x86 Isn't it true that my cpu can emulate anything?
That would be a waste of opcode space when `addi` does the job just fine. The assembler provides an `li` mnemonic for convenience, but it's really `addi`.
Would love a series.
Keen!
I did some mips at school. Assembly was fun to mess around and get close to the architecture, but I definitely enjoy the benefits of modern languages like return types.
Thanks!
No problem!
Just subscribed yesterday after finding your other video while searching for a riscv video. And today you upload a riscv one. What a coincidence 😂. I'm really appreciating your video btw.
Welcome aboard!
lmao this was so fast but it saved me from 2 weeks of not figuring out how to progress in my CPE assignment so thank you a million for the help. My prof assumes we know everything
Nicely done and explained. Only thing I personally would change is, that I would use -ld and not -gcc to just make clearer, what is happening. What you actually call is the linker, not the C-Compiler.
very easy to follow, thanks man!
I would love more videos on RISC-V. Cheers
Cool stuff! Looking forward to the next videos!
Awesome, thank you!
@@LowLevelTV I like your use of qemu, so no need to obtain (new) hardware all the time to try something. :) The ESP32-C3 is based upon a RISC-V core, so if you ever want to turn to HW this could be a nice option. I think also the Bouffalo (no typo) BL602/BL604 could be interesting. Finally I'd like to see a scenario where the code segfaults (or similar) and debugging this with jLink so that we put the assembler knowledge to good use (working through the backtrace, fixing the root cause).
The length of the ascii string is 12 IMHO. (was 13 with comma). It is accessing (and printing) one more character, potentially beyond process' address space, I am guessing ELF executable is padded to 512 byte blocks or something. Methinks you could get an exception from kernel if your 13th byte is outside process space.
Wow you’re right. He says “ascii terminated string” at 9:30, but .ascii doesn’t add a null terminator. He’d have to use .asciiz instead. He must have gotten lucky because it didn’t cross a 4k page boundary.
In the GNU assembler it is .asciz and not .asciiz, you can also use .string.
# ./hello
# echo $?
13
# ./hello
hello world
A#
# ./hello
hello world
A#
# ./hello #13 --> 12
hello world!
#
the luck char 'A'
how did you run a risc-v compiled executable on your host machine directly like "./hello" without passing it to qemu-riscv64? Is there some trick that your Linux host is using that I'm not aware of?
@@lis6502 thanks Mike, the question was still bugging me till this day
@@kkenzuro Mike's message is gone and I so need their wisdom ;~;
@@Naaronn digging old emails from youtube noti in my mail box and found his old comment:
> keywords to lurk more: binfmt_misc and qemu user mode very handy to be honest ;)
@@kkenzuro You are too kind
I love this series.
Looking forward to more videos on RISCV! Can you make a getting started video, with resources for the interested to explore on their own? Also any cheap hardware to run risc programs directly?
Gem5 is a binary library you can run riscv simulations - runs natively on Linux tho
Great video! I had a question maybe you could answer. Wouldn't the li instruction be better than using addi when one of the operands is 0? Like, instead of "addi a7, zero, 64", you could just do "li a7, 64".
You could easily do that as well!
@@LowLevelTV Oh, so there’s no behind the scenes difference or anything? Just up to the programmer’s preference?
@@kevinescobedo5633 Even if they produce the same result, they are different instructions. In the physical chip, they would behave according to their specifications, and there could be minor differences, like the number of clock cycles taken or the flags affected.
@@LowLevelTV big brain time
@@kevinescobedo5633 li is a pseudo instruction that gets converted to "addi a7, x0, 64" behind the scenes. So using it is more concise, but it eventually becomes the same thing so in the end it is just user preference.
Great job!
Thanks!
This typical person who loves retro music like "Astrophysics" channel, which is my taste too :)
This video is very helpful! Thanks!
Can you drop in what the compiled opcode bytes look like? Curious to see how the compiler outputs the memory address and the opcode bytes... I've done a lot of development in HLL but assembly only on 65C816-class CPUs.
using .asciz instead of .ascii
hello: file format elf64-littleriscv
Disassembly of section .text:
000000000001010c :
1010c: 04000893 li a7,64
10110: 00100513 li a0,1
10114: 00000597 auipc a1,0x0
10118: 01c58593 addi a1,a1,28 # 10130
1011c: 00d00613 li a2,13
10120: 00000073 ecall
10124: 05d00893 li a7,93
10128: 00d00513 li a0,13
1012c: 00000073 ecall
0000000000010130 :
10130: 6c6c6548 .word 0x6c6c6548
10134: 6f57206f .word 0x6f57206f
10138: 0a646c72 .word 0x0a646c72
1013c: 00 .byte 0x00
1013d: 0000 .insn 2, 0x
more tutorials on RISC-V please.
Nice work ! Thankyou. I have a question. I was looking at learning Risc 5 assembly language to enable the programming of one of the ESP32 MCUs. Is it possible to disable absolutely all interrrupts on these chips so that my time sensitive code has no interrupts at run time ?
I'm an experienced ASM programmer from the Atmel AVR world.
those syscalls look interesting
TOTALLY AWESOME! The coding in RISC V looks quite neat. Could you write THE SAME thing for an ARM 64, like it would compile on a Raspberry Pi4 on Linux? That way it would make it super-easy to learn the differences of the basic assembly infrastructure between those processors. Do the ARM64 people also have a convention with 8 function parameters to start with, or it comes on the stack? Also, you MAY have done this already, and in that case, could you point me to that Hello World ARM Assembly video? I'm such a newbie... THANK YOU SO MUCH. I really like your low-level-learning series, it always comes in small chunks that one can really understand...
Looking forward for more tutorials on RISCV .
It would be helpful if you can reduce your pace a bit.(I felt it was a bit fast)(just a friendly suggestion)
I definitely tend to talk fast. Thanks for watching!
Change playback speed is the deal. .5 works just fine.
I totally disagree; I put this on 1.5x speed.
Also - I see you used section 3 of the manual for exit(). I haven't really done much Linux syscall programming but shouldn't we check section 2 in this particular case?
Well the interfaces in section 2 and 3 are pretty much identical, forgive my pedantry 🤣
You're right, for syscalls it should be section 2. Section 3 gives the right answer for exit by good luck, but not for write (doesn't exist).
hmm interesting i want to learn MIPS but this looks interesting RISC-V when it is more developed and has a larger community i might give it a shot
The miscounting of string length here highlights the general issue of having to count the string length manually, which is already difficult to get right at 12 bytes. Are there any tools in the compiler or IDE set-up to automate this counting for longer texts etc. ?
make more of RISC-V, i wnat ot learn it.
I wish you showed how to set up and invoke QEMU, and where to get images.
No image is needed to run bare-metal programs like this. If you want to run a RISC-V linux then see e.g. wiki.ubuntu.com/RISC-V or if you have Docker installed (on x86 or arm64 machine) try: "docker run --platform linux/riscv64 -it drujensen/riscv-ubuntu bash"
Do AVR and 6502 :D
what was the whoosh at 0:27 seconds?
Is there a version of Basic for RISC-V yet? I was hoping Purebasic would have already been there but unfortunately not.
Hello, as usual nice video. Just a small question, is -static really required when linking these examples?
Nevermind I watched the arm64 episode where you explain why 👍
It is when using the Linux compiler, which creates a dynamically-linked executable by default. Doing programs like this -- especially for an embedded board -- you'd probably use riscv64-unknown-elf-gcc instead, which 1) automatically links statically, and 2) uses Newlib instead of glibc (of course this program isn't using the C library at all)
There is valuable information here, especially about how to make Linux calls from within a program, but you are going to learn very little riscV assembly instructions. Just a couple of opcodes.
So let me get this straight. Internal computations are not "meaningful" because they don't talk to the Kernel. 95% of all computations are internal so there is no point in writing applications because most of your application it is not "meaningful".
those 95% of computations eventually lead to kernel interaction, so they become meaningful
Looks as though startup and exit could be boilerplate or macros. How good are the macro/subroutine features of the Assembler?
Straight to the point
I set the speed of the video to 1.25 and I learnt RISC-V assembly in only 8 minutes! 😜
You had my enthusiastic attention until the syscall section and the realization that you are really just messing around with the Linux kernel using assembly language.
I'm glad others enjoy, but, to me, low level assembly programing would not involve a kernel. Making underlying software do the heavy lifting for you is the definition of high level programing.
Nice video! One question, how and where did you find the "qemu-riscv64" command? All I can find in my system is "qemu-system-riscv64".
I'm on Arch Linux and I downloaded the following packages:
* qemu-system-riscv
* riscv64-linux-gnu-gcc
Also, how do you even execute the program without using "QEMU" at first? What kind of black magic is this?
Exactly same question here. This is blocking me from following this tutorial, because I kept getting "Exec format error" if I follow the tutorial and simply run "./hello"..
@@yltfy Hope he replys at some point!
@@godnyx117 You need to install qemu user mode. This worked for me In Fedora:
sudo dnf install qemu-user
then you run things with
qemu-riscv64 ./hello
The cool thing is that once I installed qemu-user, I don't even need to type qemu-riscv64 as the loader gets a hook that knows to run RISC-V executables via qemu-riscv64.
For Ubuntu, the package is also called qemu-user I think.
@@pierrejacomet8098 Why the FUCK didn't he said it in the video? Unless the package was split after he made the video...
Anyways, thanks a lot for the help! It will come very useful in the future! Have an amazing day!
@@yltfy Check the reply section, we got the solution! TLDR: You need the "qemu-user" package!
Is there no load immediate instruction to load a number into a register? It's quite a common thing to do, even in this trivial example. It seems a bit clunky that you have to add it to zero. How many cycles does it take?
The assembler provides an `li` mnemonic but it's not a real instruction and for values between -2048 and +2047 it expands to an `addi` instruction. Clock cycles depends on the design of the particular CPU, not the instruction set, but you can expect that no other instruction is faster than `add` and `addi`. On CPUs designed for speed that's going to be 1 clock cycle.
Dude. What's your Patreon? Can't see it linked in the about channel page?
Cool! I literally have not seen any RISC-V, you are popping my cherry 🍒:)
Thank you! Cheers!
Thanks
Is there standard BASIC for risc-v such as GAMBAS or similar ?
Fred: "Alright gang, let's see who RISC-V really is!"
MIPS:
MIPS have abandoned their proprietary ISA(s) and have already announced their first high performance RISC-V CPU. They know how to design hardware, but they couldn't maintain today's expected software ecosystem alone.
@@BruceHoult It's a joke
@@williamdrum9899 jokes are supposed to be funny. If it wasn't for you damn kids they'f have got away with it.
Can you put the links you reference in the description?
Using qemu by the way
Why I can't emulate newer cpu models on an old machine
Ex: can't emulate 8th gen x86 on 6th gen x86
Isn't it true that my cpu can emulate anything?
i makes sense that you cant emulate it, but i wont tell you why it makes sense.
@@QmVuamFtaW4 is there a way to bypass this issue?
yes, but i wont tell you.@@jirehla-ab1671
Why would you do rm -rf for deleting a simple file?
To add jeopardy! It's a bad habit to get into.
I got lost at the first part I am still trying to learn..
did not understand the use of syscall 13 in the code
@@lis6502 Yes, I believe it was just an arbitrary number to show that the exit code worked. It could have been 99. Or zero.
synthwave 84
I tried to run the first program but encountered a problem:
"bash: ./hello: cannot execute binary file: Exec format error"
Any idea why?
Looks like RISC-V has no load immediate value instruction.
That would be a waste of opcode space when `addi` does the job just fine. The assembler provides an `li` mnemonic for convenience, but it's really `addi`.
Me making a shitty instruction set in a week:
have to play at 1.25x to avoid the vocal fry...
Assembly language programming is a dead end. Jump straight to the C programming language!
some of us grew up on Z80 and 6502, oddly, we find assembly programming fun!
If no one learns assembly programming, who's going to write the C compiler?
Thanks 😊👍