Want early access to new videos and some behind the scenes content? Consider becoming a channel member ruclips.net/channel/UCQvW_89l7f-hCMP1pzGm4xwjoin
This reminded me of the time a colleague thought he could rewrite his C code in assembly to get more performance, what he learnt at the end was that the C compiler optimisation was much better than his assembly coding skills.
yeah compiler nowadays are really smart though, normally when you write your C code and let the compiler optimizes it aggressively, then you compare to your asm code, it's just no competition
Every time someone finds a cool way to optimize assembly code, they just add that optimization to the compiler. Modern compilers are just effectively 20+ years of knowledge packed into one little box.
Yeah, there are only very rare circumstances in which you could get any speed gain by rewriting something in Assembly. See for example Lua vs LuaJIT, where LuaJIT's interpreter is written in Assembly in order to store some important state in the same registers while the interpreter is running, and to speed up the fetch-decode-execute loop as much as possible. No C compiler can do that kind of thing at the moment.
This is the kind of comment that I find very strange. I think that people just haven't thought through what can be optimized and what can't, but everytime that I _thought_ that I could out perform the compiler, I was correct. I don't feel like I can do any better most of the time, however.
What makes compiler optimization so great is its not just a single bit of contributed ideas from a single person whose smart in the field of assembly, but its a collection of all the smartest techniques anyone could functionally think of to optimize your code, as a result the compiler is the culmination of every idea of almost every geniuses' demonstrably proven optimization technique, its basically the collective execution of every single engineering wizard in a singular binary who also knows exactly how to evaluate your code most efficiently almost all the time. (granted we assume all compilers do the same optimizations to low level machine code, which outside of edge cases and small processing differences that's pretty much true)
I’m 59 and wrote my first program in an assembly type language in 1977. We are truly standing on the shoulders of giants. I am an aerospace engineer, but still need to write code to automate engineering tasks. Visual Studio is my environment of choice because it makes my job so simple.
I recently switched from Notepad++ to Visual Studio (not Code). I am surprised how bad it is at basic tasks, like search and replace (it's slow and half the time doesn't replace or skips one replace). It also takes up 700MB in memory when running.
I'm impressed. My mom was an engineering aid working at the Boeing wind tunnel facility. She had the neatest pens for plotting out the results. She claimed she got sent to take Fortran classes because the engineers couldn't be bothered.
Binary (i.e. machine code) = assembly language, or, to put it another way, assembly language is a 1:1 version of machine code using opcode mnemonics. Crucial note: all opcode mnemonics are known during the CPU's final design stage - writing in 'machine code' = writing using the numeric values of these opcodes. Assembly language is, essentially, writing machine code using the human-readable mnemonic text version of opcodes. No one writes in 'machine code' - it's all assembly, and always has been (on paper in the 'early days', with the machine code translated version along side ready to be loaded). Of course, an embedded system (e.g. space/satellite etc devices) will be pre-loaded with the 'assembled' (i.e. binary) version of a program.
@@ChrisM541”no one writes in machine code” That’s weird, in my FPGA class everyone wrote in machine code. Except me because I wrote an assembler, but an assembler doesn’t always exist. And even my simple assembler generated machine code that didn’t map 1:1 to assembly. You don’t know what you’re talking about.
I can write something like this in C without ever looking at a line of doc or doing a Google search while I feel everything looks complicated in C++ and I spend a lot of time searching and doubting myself. The fact the author feels a class of library was helpful for this leaves me perplex as well... when all you need is a few structs and arrays.
It's worth learning C and/or assembly, to better understand how computers work at a low level, and because C in particular is used everywhere. It's worth learning Python and Rust and Javascript, for their respective tasks. But it's probably not worth learning C++ any more. Other languages do its job better.
i just took a look at your code and for some reason the assembly one looks way cleaner and simlper than the c++ one, at least for me. congrats on the readability of the asm version
Well to be fair when writing assembly you obviously want to write as little code as possible, so naturally it's going to be cleaner because less code = less chance for spaghetti to cook 😂
>Using a linked list to write a breakout clone What is it with you modern, high level 'programmers' that feel the need to shoehorn random memory structures into your programs? You can write breakout with just statically defined, bss memory - you can even use bits in a calculated grid system for the blocks to maximize cache utilization in the collision detection and make massive games that still run fine. This is the thing about assembly that many people don't seem to understand: you control exactly how complex it is; you control exactly how much useless abstraction you add to your system. It just so happens that simple solutions to simple problems are also usually much faster than complex solutions.
You are right, it was an active decision on my part to increase the complexity. I felt it told a better story of how each successive language made development easier by increasing abstraction, by having a common-ish design across all three. It also helped highlight how low-level and bare bones assembly is.
@@nathanbaggs Maybe so but it also failed to highlight one of the largest benefits of programming in such a low level, namely the direct incentive and ability to write said program in as few instructions/using as little memory as possible. You, in fact, directly contradicted it by exclusively focusing on its flaws. The whole point of programming in assembly, these days, is to write extremely tight code with (optionally) tight memory constraints. Being bare bones is both a good and a bad thing but I saw very little good. In fact I don't think I saw any at all. It's quite one-dimensional, this analysis of assembly programming, and it comes off to me as forced, like you were trying to form the narrative to be only what you wanted it to be. I'm not saying go full jargon but misleading your audience just to tell an appealing story is exclusively targeting the lowest common denominator and is degrading to the heuristic knowledge of people who don't spend their days programming in assembly.
@@handleneeds3charactersormore He meant That he isn't able to finish writing up Python scripts in as short amount of time as the creator can in assembly
Trying to wrap my head around how confused you would have to be to implement a linked list in assembly, or why you'd implement an allocator for a small dataset with a static maximum length.
I'd say an x64 processor has so many registers that you don't really need memory for a simple game like this. You can store 8x8 blocks in a single 64 bit register. Xy position in 8 bits each, direction in 8 bits and the bat in another 8 bit and maybe score in 16 bit all mapped into a single 64 bit register. You'll need 'vram' at some point of course, the console in this case. The fun thing of 8 bit home computers like msx, c64 and spectrums was you can write directly to the display buffer, make use of sprites, add some sound etc without having to do system calls, or just console calls the the bios/rom. There are probably ways to access libraries from assembly to do syscalls but that's a whole different can of worms.
A really useful challenge for me was taking something as simple as a linked list and go from Python to C++ to C and assembly. On the way i dropped a view things like C++ had a dynamic type and a static typed version. C and assembly only had static types. And i always used the the knowledge as well as the generated code from previous versions. This challenge really lets you think about what you are actually doing with high level features.
Can’t be disagreed, when I first learnt assembly I fall in love with it, but as I go I was trying to build more complex stuff like floating point arithmetic, and visual stuff it just sucked , because I have to implement everything from the scratch. Any event it’s amazing work you have done , thanks for sharing.❤❤
@@abz4852 oh god, fuck that language it's a very similar experience to what the original comment has described, but it's many orders of magnitude slower and _incredibly_ restrictive
I’m a bit lost as to why you would need linked lists for breakout. Breakout is a game that could be handled pretty easily using only the data segment to define your static array of bricks and player tokens. Biggest pain I foresee is the gameloop, graphics, and IO but none of that should require dynamic memory.
Sure it might be a bit over engineered, but I had a rough design that I wanted to implement three times - and that included a dynamic data structure. So maybe my phrasing wasn’t accurate, I didn’t “need” a linked list. If I was making a “real” game definitely I’d think a bit more about what data structures I used (:
@@amyshaw893 Yes of course. But it'll need an equivalent amount of bits either way. The only difference is how you interpet them. However, linked lists in this situation will make for more indirection, more work and more memory used. C doesn't have big ints AFAIK, but it does have character strings. These can be abused to do kinda pseudo big ints. Come to think of it, x86_64 asm doesn't have native big ints either right?
@@AbAb-th5qe wouldnt a 2d array need a full byte for each element? im not sure if you can make a 2d array of single bits, plus that doesnt include the array overhead
Wasn't disappointed with this video, great work. I got a class this semester that specialises in the architecture of computing units. It's mainly aimed towards optimisation. Going from single thread unoptimised code to heavily multithreaded, optimised in all aspects, vectorisation, working with cache more effectively, reading less and what we need. Understanding how CPUs manage to do more per clock and how you can help it as a programmer with properly designed code. That's just something awesome. But yeah, you're not gonna expand your for loop, let it read 4 different values behind each other, because it takes three clock ticks to actually get it and work with it, so your code would do nothing. That's just a small part the work compilers do for us and I personally think that is awesome. They are written by smarter, more experienced programmers and are in development for longer than I am alive. No point in drag racing them. I got to say, had one class about assembly and I don't even know where I would start if I were to try to implement something in it, not to mention with GUI. Great video showing that going deeper doesn't always mean faster. Can't wait for the next one titled "I tried to write something in binary by hitting neutrinos with my HDD (just kidding, used Emacs plugin)"
Great video, this is the kind of stuff I work with daily. How come you keep implementing linked lists? Would a normal array not work fine here? Linked lists are often more trouble than they are worth because of the memory overhead in each element and it is comparatively much more computationally expensive than a typical array.
I went for simplicity over efficiency. I didn’t have to worry about bounds checking, resizing and copying elements (for dynamic array). Just allocate a node and wire up the pointer!
yeah: in ASM the only structure is array (possibly of records). You do not need memory management in ASM. You work on your own private array statically allocated with your program.
@@drivers99 yes sure, index is just a local pointer relative to the array. But higher level structure aren't natural in ASM. Better use data structures better suited to your language. Low-level langage imply low-level data structure.
One thing you did in your code that I've never thought about doing is writing out the function logic as a comment block under each prototype on the header file. I could see how useful that would be for other devs who don't want to drive into the specifics of every function, only what they do and return in an abstracted way.
@@nathanbaggs well, you'd be called a sucker for that because they stopped teaching the importance of documentation, as far as I know, in the last 10-15 years, because people whined about having to show their work.
Despite not writing in it since college when i used these little embedded project boards, i think my experience with assembly is invaluable. It allowed me to better understand how things work under the hood when programming in higher level languages, like C and C++. I would love to program in assembly, but it is way too tedious to do so for the code i write. We should be thankful to the creators of higher level languages who abstracted away the tedium of assembly and made programming much less tedious. Great video, btw!
Love the bit about "the assembly can only be as good as i can write it" A lot of people seem to think that writing in asm is racing stripes to make the computer go faster. Humans should do the things humans are good at and leave the things computers are good at to computers.
In the past using inline assemble did help when compilers didn't have the optimization they now have. In some instances a significant performance gains could be done. Usually instead of writing an entire application in assembly you wrote a few specific functions that are imported into C/C++.
but assembly was made for humans to write. it's what the intel manuals for x86 programming cover. people have, and continue to write faster assembly than a compiler. usually because of them making use of certain instructions that the compiler doesnt.
@@minneelyyyy So were punch cards. I don't see anyone stumping for that. As far as a human beating a compiler, maybe on a single function or optimizing work the compiler has already done, but toe-to-toe, human vs machine the machine will win every time on any non-trivial program. i'll bet my lunch money on that.
@@khatdubell punch cards are a funny example considering that no modern computer can even understand them, thats very clearly an old technology. assembly, however, is often benefitial in small amounts. it is necessary, too, for things like osdev or writing low level code for the os.
@@minneelyyyy Compilers will used advanced instructions. It really depends on setting the compiler settings. About 25 year ago C compilers defaulted to the 386 or 486 instruction set, and if you wanted to use the extended instructions of i486, Xeon, you had to enable the compiler setting. The issue with using extended instructions was that a lot of machines had processors that didn't support the extended instructions. I believe today compilers all have the extended instruction sets enabled.
Well if you code in assembly with a c++ mindset no surprise you'll find c++ more comfortable. Same happens if you come from python to c++. Not to care about pointers and memory allocations is a "breath of fresh air" in python after c++. However if you do care about efficiency you'll find python frustrating, since you can't controll what the computer is actually doing. So if you learn the c++ mindset you'll find python extremely limiting. The same applies to assembly: if you wanna squize the last bit of performance out of the computer you'll find c or c++ limiting after assembly. Of course it doesn't really apply to moder PCs but could be a real issue with programing microcontrollers, 8 bit retro computers or other devices with limited resources.
Yeah for one thing I was like why TF do you need a linked list for a breakout game??? For the assembly part you could just do what people do for retro PCs and just take a big chunk of heap memory and slice it up into a memory map for the game to use with pointers for each part, one part of the memory can be for the ball, one part for the bricks, etc, there's no need for a linked list or any sort of fancy data structure like that for this simple type of game...
hey man, first, congrats on making something that complex in assembly without years of experience in it! I feel like you took a very wrong approach to coding in it and C though. The first realization should have been that you don't need a linked list, or a malloc, you need only do the steps required to run the game, just mapping a few memory pages and getting a pointer to the window vram from the kernel is all you should really need (as well as communication messages between the os and you but you had to do that regardless). Ofcourse working without the niceities is tough if you've never done it before so it seems like the only thing to do in x86 assembly is to look at it and start your IDE with a normal language on it, but there are still very good uses for assembly programming, though not directly in assembly. What is done (most commonly in the games industry because that's one of the last places where getting everything out of your computer matters) is you take a very unoptimized problem, you shrink it down through regular optimization, and then you apply SIMD to it. What's that? Yeah there are special assembly instructions a C compiler will never use, unless you tell it to, and even then unless you structure your data right, it won't get to use them. These instructions can process whole arrays of numbers or even matricies of numbers at once, there are instructions for ray intersections, for regex filtering text 16 letters at a time, cryptographic functions, all these can be done by specialized wiring inside the cpu extremely more efficiently then any high level code could. And that's mostly the only place assembly should be used, because as you've discovered, it's a pain. Thanks for sharing it with us!
I might have over engineered the assembly design a bit, which has been pointed out in a few other comments. But I wanted to see how easy it was to create comparable solutions across the three languages, which includes dynamic memory allocations. I wouldn’t consider myself an assembly expert but I’ve read/written enough to get by. So I’m familiar with SIMD, etc.
All this is way over my head, I used C in the past but that was in the eighties running on SCO Xenix. But I do remember the code for this same game written in the Basic that came with the first gen Apple 2, I doubt if it was much longer than 30 lines due to the graphics and paddle capabilities that Woz built in when he wrote the language. It ran seamlessly on a 1Mhz CPU with the 32k Ram I started out with.
Why would you need malloc to code a version of Breakout in assembler? Surely everything would just be statically allocated and you don't need anything more than simple arrays to represent the set of bricks on the screen (e.g. 1 byte per brick with each brick within a grid: 14 column x 8 rows). An early assembly programmer wouldn't even do that, they'd allocate 1 bit per brick. Then you'd first check the location of the ball: ball_y>=brickmap_y; && ball_y
I think I could have been more explicit with my choice of words, I certainly don’t “need” malloc. I had a rough design that I wanted to implement three times and that included something non-trivial like a dynamic data structure.
Thought it was gonna be one of those nonsense "writing the same game, using the same source code-ish to see the difference between C and C++" but the fact that you actually leveraged what C++ does so great (like RAII), anonymous namespaces, etc, makes it rather refreshing.
You didn't need a linked list (an array is plenty for your game) and you didn't need to implement x11 directly. C doesn't provide graphics libraries any more than assembler does so if you allow yourself to link libs in c then you can allow yourself to link them in assembler.
Come on, you can use any C/C++ libraries with assembly too. Maybe it's not very easy, but coding in assembly doesn't have to mean coding every single part of the code in assembly. For me the most effective way to code something like a game is mix various languages. Where you need high complexity - high level languages, high performance - C++, C, assembly. I found C# is like perfect for some complex (or dynamic) data structures, high-level protocols handling, but it's not good to just push bits from one place to another with consistent timing. C is perfect for pushing bits reliably, but handling complex things with it gets tedious. C++ is something in between. The speed of C, but it's a little easier to add some more complexity without writing too much. BTW, C flavored C++ is a cool thing. You just use C++ like C with namespaces ;) That approach works surprisingly well in some scenarios.
I'm curious why you implemented malloc for the x86 version? I've done some simple games targeting wasm without libc and had no issue just putting everything into a statically allocated buffer
You’re absolutely right I could have done that. I wanted to try and keep the three implementations similar - C and C++ used dynamic allocation so I wanted to see what it would take to do that in x86.
@@nathanbaggs Conceptually I understand, but as a counterpoint you have programmed in C like a C programmer, in C++ like a C++ programmer, and in x86 like a C and C++ programmer. You've made a good video. I was expecting to see a comparison of programming languages paradigms, and didn't find that.
@@PhilipBarton He also could have put everything into a statically allocated buffer in C and c++. Its not "thinking like a C programmer" to dynamically allocate memory. Its part of writing more than a basic program.
@@khatdubell the simple approach is often the best one, a "basic program" is what you should aim for. If there is no need for dynamic allocation, doing it just makes you code objectively worse.
@@marcossidoruk8033 only using static allocation isn't a solution tho. It still makes things complicated, because you need to separate it into chunks. Same thing with dynamic allocation, using mmap gives you a page of memory (so 4096 bites) that you need to cut into chunks. You could very well just ask mmap for way more memory memory a single allocation and then do your thing. At the end of the day, mmap will return you consecutive memory because of the layer of kernel abstraction around memory.
Always remember the costs associated with the coding and maintenance of the code. But that is part of losing knowledge, people are forgetting the basics learned from the 1960s through 2000. Great video again!
In the '80's it was easy to write apps in Assembly that were faster than C. Since then the microcode in microprocessors got far more sophisticated. The longer pipelines & similar sophistication are things that compiler writers spent a lot of time optimising their output to take advantage of. But you have to think of all that with you are also dealing with the logic of your code. Thats tough.
In assembly you have access to all the standard Microsoft libraries and with a decent Macro Assembler like FASM, you have macros to handle those function calls. Moreover something like tail call optimization is usually just a jmp call in assembly, while impossible in C, unless the compiler provides it. Some of those macros are pretty powerful and you can actually be productive in assembly. The main problem is that it's not portable.
I found this video extremely useful Nathan, thank you. I had to put a SDL_Delay(1) statement in the running loop as it was impossibly fast to play, and cpu usage was very high - unless I did something wrong? I also had a compiler warning in c_window_destroy line 79. “Potentially uninitialised variable” - fair enough! I commented this line out for expediency. The hardest part of this was installing the SDL lib. I was stupidly trying to build a Win32 using the 64 bit SDL lib - silly me!
If you do not give CPU time explicitly in an infinite loop (for instance by SDL_Delay(1) or any other "sleep" function), CPU will be consumed with 100% (at least on one core), as task scheduler will always give immediate control to your application (unless there are other applications which are in active state and have prio equal or higher than your application).
Every time the ball hits a brick you have to append a 1 to a linked list, this is necessity for Breakout. Otherwise, you can't really call it Breakout.
The asm version appears to run slower than C/C++ versions. That says alot about compiler optimization. I would try turning off optimization, compiling and running to see if that makes a difference
More likely, it says things about data structures or algorithms build into C/C++ libraries. If it was code for code, compiler optimizations on a game like this would be minor.
30 years ago I was writing games in x86 assembly. I was 18 at the time and it was exciting to have a level of performance that I'd never been able to achieve with stock libraries that came with my BASIC and C compilers. But... yeah, that's a lot of extra work. I very quickly switched to writing my own graphics libraries in assembly and writing everything else in C. Kids today have it too easy. I could rewrite that entire project in C# in a weekend.
You can use libraries and call functions in ASM. If I'd been writing in ASM, I'd have used SDL and libc. Just because you're writing in one language doesn't mean you can't call functions written in a different language.
Many thanks aks for sharing your AMAZING project 👏👏👏🔥✌ Please consider making end-to-end tutorials for the whole project. 🙏 That will be extremely helpful for c cpp assemly learners. Maybe more similar projects in the future Many thanks in advance! 👍
Why would you need a malloc and a linked list for a simple breakout ? You only need a fixed amount of memory to store the level and the graphics. Just use data and bss sections. Anyway I never coded in assembly on Windows but I'm pretty sure there are Windows functions to allocate memory dynamically.
You’re right, you don’t need it, I think I could have been a bit more explicit with my choice of words. Also something I could have been clearer on is that this was written using WSL, so it’s all Linux syscalls.
I wanted to implement a simple data structure and for me linked list is easier to implement if you want to remove from the middle of the container. I appreciate an array is more cache friendly and more efficient for iteration.
It's funny that lots of early games, especially consoles, utilized assembly because no one had the budget to make a whole custom C compiler for their hardware with very specific features. Even as C finally started taking over, inline assembly was still common. Unless you were working on some big UNIX machines, you had to use assembly for the performance because there just wasn't an optimizing compiler available. GCC was a game changer when it released.
insightful experience. You should try to that similarly using Rust, it's not very different from C++ (you might need to "let go" some C/C++ concepts) but it's interesting language (kinda boring also, but the safety is worth it).
The amount of people in the comments mentioning rust was not unexpected. It’s on my todo list to learn, I want to spend some time with it before I can do a fair comparison
Okay, I have to ask, why did you have use malloc in ASM? It sounds like you litterly reinvented the wheel, because of your familiarity with how you are used to doing things. Having coded in all 3 languages myself here is what I can say. Don't expect any hand holding in ASM, if you're doing things the same way you did it in a compiled language you're probably doing it wrong. Examples are, coding while using a compile anywhere mentality. ASM by definition is machine specific. Your targeting specific hardware, using a specific OS. Once you realize this you will find in every OS a specialized memory management API. You then have to think how that API is meant to be used. Then make it do what you want. At my peak I got to 50/50 when comparing my code to compilers. Half the time I could beat them in both size and execution speed. It only got better if I peaked at their output and used that to optimize mine. You probably have no idea how often compilers tend to add a ton of unessarry stack management. If your good you can manage your entire stack with math and free up your stack frame register to be used as a generic register. C is the baseline I compare all languages against. Its simple no nonesese calls and structure generally makes this one of the simpler languages to work with. C++ is what I use when I need lots of easy to implement data structures. Of the 3 languages this is the one where data management takes the foreground. This might be a bit overkill for a breakout game. As most of your data structures are ideally just arrays. So if I were to equate the languages as tools to move boxes. ASM is using tweasers, C is just picking them up manually, and C++ is the forklift. And don't get me started on what you can do when you realize you can export libraries in c and c++ to be used with ASM, and you can use inline ASM in both C and C++. These languages are litterly interchangeable.
This seems to be out of the scope of the video but I'd be curious to see some sort of performance benchmarks in terms of FPS comparison between all of them! Would be cool to see how little or much the pain of low-level programming is for speed.
Language won’t give you any speed benefits considering today’s optimizations within the compiler. Listen to Lex Fridman podcast with Bjarne Stroustrup and he talks about this.
@@jorgeherrera1074 Depends on your compiler, really. For Arm, Intel, Power, SPARC, etc. there's rarely any chance you'll outperform the C compiler. Some lesser-used architectures don't have any good C compilers (or charge a fortune for them), so there are still places where hand optimization is useful. PIC comes to mind here - I don't know how it is now, but back in the day the only free compilers available weren't very good. You could pay for better ones, but it wasn't cheap for a hobbyist. I suspect that's a major reason the ATMega got used for Arduino over the PIC, which was more common in the industry.
and @@jeffspaulding9834 also very good to know that this is not always the case. I'm curious to know what hardware has unoptimized compilers. I rarely write embedded software so hopefully I should be safe using the C compiler most of the time!
@@bren007pie2 PIC is the biggie - if you don't pay for Microchip's compilers, you're stuck with unoptimized code. I looked around and things seem to be improving. Lots more microcontrollers have gcc or clang support these days. Some manufacturers still recommend commercial compilers, but gcc seems to be gaining a lot of traction.
i might be the old one here but i remember writing a breakout game in ASM and i had no issues with memory to get more banks or issues with the data as i could get away using the video memory instead of an array of blocks. and a counter to know if we ran out of blocks. and it was running just fine - sure there was no windows / gnome (x) to worry about as it was dos based, but if anything it was TOO fast, so had to slow down the bounce to whatever millisec to be playable. (of course C compilers are making much more effecient compiles, but it does not make a difference at such a low complexity game and where you have to slow it down anyway) and we are talking about 8MHZ cpu speed and not 4.2GHZ with 16 cores :) i agree writing the code is easier on higher level languages, but i reject that there is no fun and excitement working in ASM. at least for me it was fun
True. What is hard to see here is the fact that writing in such a low level language as assembler in such a high level operating system feels very obsolete. I also think I sound like the old one here, but when you have nothing but a blazing fast 20 mhz machine and a brand new, 1000$ EGA graphics card, you'd LOVE this low level ability to manipulate any register to your likings, twitching and twisting the bits around, just for this one, little more of speed you MIGHT get out of it. It's like playing with lego blocks, a craft with a very hand made feeling to it.
I think I could have made myself clearer in the video. Instead of “I needed a linked list” I should have said “I wanted to write a linked list” - and the reason for that is I felt it told a better story of how each successive language made development easier. As you and others have pointed out, there are alternative/simpler ways of storing data.
@@nathanbaggs Don't get me (us) wrong we are not here to fight or lecture you :) the mere fact that someone is still attempting to do ASM is great :) But on one thing we are going to disagree :) Actually your attempt did not show the real picture of how each language made development easier. See forcing linked list on ASM is something absolutely not language 'correct' I would say using the standard ways of storing data would have showed how different and what benefits the new languages are bringing. I mean once you had your linked list library, its frankly no different on the surface than calling some high level functions in C / C++ since now you HAVE it thanks to your library. What your approach showed that ASM is capable of having whatever a high level language has, but it does not show the real progress. i mean this is a good example: call cls jmp $ cls: pusha mov ah, 0x00 mov al, 0x03 ; text mode 80x25 16 colours int 0x10 popa ret (copied from stackoverflow for easier reference) this is what you did with the linked lists. :) But now there is no difference between invoking a high level CLS or this here... So in fact you blurred the boundaries :) i think what would have made more sense is to show how you get data in and out from say the graphics card memory to handle collision detection and then show how much easier it is to use an array or a linked list. the same would go for keyboard handling, or writing text on the screen... etc :) anyway, it is a good video, so keep up the good work :) you are onto something here and i am sure great success is ahead of you :)
@@luicecifer I agree, coding in assembly in the day and age when you have layers upon layers between you and the hardware is obsolete for "everyday coding". but it has the benefit of learning how actually the CPU is working under those layers. it might help someone to think when they write their highlevel code. (lets talk about the predictions the CPU makes and calculates ahead just to throw away everything it failed with the predictions - IF statement in a loop for example) For non everyday coding however where every cycle counts assembly is the best friend besides C / C++. (when maybe a millisecond decides between a disaster and a successful landing on Mars - and you can't afford running a multilayered system for limiting errors and resource eating) :) :) and ASM is such a highlevel coding compared to punchcards anyway :D :D
This looks like a C++ programmers investigation of what it takes to implement their high-level language features in lower level environments. Which is fine. But I think it misses an opportunity to investigate the different approaches to problem solving that are appropriate for those lower-level languages. Why use dynamic linked-lists in assembly or C? Just allocate static arrays of data. What's the difference is implementing graphics (quite hard in assembler, would have loved to see how you managed that). You lament the lack of fancy data structures in assembler, but really, you don't need them for something like this. With assembler, you can write breakout that runs on an Atari 2600. You can't (easily) do that with C++ (without a modern computer capable of very fancy compilation and very new C++ compilers). It would be worth considering the advantages and tradeoffs of each level of abstraction. There's a reason the linux kernel is (mostly) written in C, not C++. It would also be really interesting to see a comparison to more modern high-level languages like Rust and Go.
Because he obviously programmed it from top to bottom then studied the converted C and compiled assembly code in order to make this video. His C code smells of a poorly done conversion from C++, and NO ONE who understands assembly would ever even dream of using linked lists the way he did.
While C/C++ compiler optimizations are usually faster than normal assembly code, note that optimized assembly code will be faster than C/C++ compiler optimizations.
The advantage of assembly code is that you only write the code that is needed and the assembler turns mnemonics into machine executable instructions. Higher languages rely on libraries which are general purpose, parameterised routines that include a lot more code. Then libraries are written that rely on the inclusion of other libraries... Yes, it makes the coding easier (read "achievable"), but less efficient. Hence we need super-powerful 64 bit cpus and super fast memory just to present a desk top. I taught myself z80 and 6502 code in the '80s and progressed through a career in COBOL and similar 3rd gen languages in the '90s and '00s. I haven't written code in decades. But the fact remains that the nearer you get to the metal the more "immediate" the execution becomes. However, trade that off against the difficulties of coding at that low level (the Roller Coaster Tycoon that others have discussed). But you can write crappy inefficient code in any language, so speed of execution isn't just a property of the language. The driver behind current languages is speed to market, not speed of execution.
As someone who started to learn programming on ZX with 48KB I have no idea why you needed the linked list. I have a feeling you coded in assembly as if it was C++. Breakout doesn't need linked list, malloc or free. All data is statically known. Bricks can be handled using a static array(which is so small, it can live in stack), removing a brick can be done in a way similar to erase/remove idiom (swap N-th with the last, then pop). Maybe X11 needs something special, but then again - why did you use X11 and not SDL like with C/C++? I'm not fan of asm, especially when now instructions look like you roll your head over your keyboard(PCLMULLQHQDQ), but I feel at least half of the struggles were caused by overengineering a program.
That’s a fair point and one that a few people have mentioned. I wanted to compare the three languages, including using/implementing data structures - and I figured linked list was easiest to implement. In a “real” game I’d think a bit more carefully about the choice of data structure. I think I could have made that clearer in the video (: I agree it is a bit over engineered, but that was almost by design
The assembly frame rate is bad because it was a really basic game loop. For C and C++ I’m not sure why, I didn’t notice till after I the rendered video. I think it might be an issue with how I recorded it, lesson learned for the next video (:
@@stephenkamenar yeah that doesn't quite add up lol, even if the code was really bad I doubt the fps would be as bad as it is in the video, then again they did think it was a great idea to have a linked list for something as simple as a breakout clone that doesn't really need something like that in the first place so who knows, maybe there's some other unnecessary thing in that "simple game loop' that's causing it though I couldn't really imagine what 😂
To all those who extoll the virtues of compiler optimization - yes, it does a lot, but if you're doing any kind of SIMD or MIMD favourable maths, you can seldom beat hand coded assembly, even if you've qualified every line and used aligned memory. Even intrinsics don't always cut the mustard, but they can get you a long way.
Damn I thought you had like 200k subs or even more judging by the qualities of your videos. You have earned your self a new sub Ps could you make tutorials for c++ :(
Thanks for the kind words! I've been considering making some tutorial content, do you have any specific part of C++ in mind you would like tutorials on?
For such a simple project i'm not sure why you'd need dynamic allocation nor linked lists. Given that all levels are statically allocated on a fixed size grid.
You’re right I could have simplified it. I started off with a rough design which I wanted to implement three times, and that included something non-trivial like a dynamic data structure. It was fun seeing how each successive technology made development easier.
Not me sitting here struggeling over my assignement for "Introductory to programming" class in uni using C and this guy goes. "C was a breath of fresh air". Pointers and structs have become the bane of my existence
Yeah pointers are an odd concept to begin with but the best advice (or at least what helped with me) was to just write some code using them, simple data structures like a stack or a linked list are great for learning and getting your head around them. If you can't start there, look at some existing data structures and mess about with them. I've learnt everything I know from doing rather than reading. It just takes time and practice. One day it will just click and start making sense. I didn't think I would get my head around C but I did, I didn't think I could write anything in ASM but I have and I certainly never believed I could write my own language from scratch but eventually that was ticked off my list too. If you want something badly enough you can make it happen, I'm sure you will too.
If you approached the asm with an old school mindset you would have simply skipped the malloc and linked list for a project this simple. Neither would be necessary. In simple systems we used and reused static buffers defined in the assembly directly, and linked lists if used at all were usually using embedded pointers in the statically allocated objects. Though right enough larger systems typically ended up writing much of the same code a C runtime includes. FWIW once the C compilers evolved enough to generated decent code, everyone, barring a few stick in the muds, switched to using C with asm used only to enhance performance where it was most needed.
It was introduced in C++17 and was a real game changer for me in terms of API design. No need to bother with out parameters. It combines nicely with if statement initialisers, so you can do: if (const auto v = func_returning_optional() ; v) { }
why would you use a linked list instead of a simple grid array and a 'remaining walls' counter? It's much easier to implement, faster, more memory efficient and doesn't require any mallocs
That’s a fair question and one that a few people have asked. I wanted to compare the three languages, including using/implementing data structures - and I figured linked list was easiest to implement. In a “real” game I’d think a bit more carefully about the choice of data structure. I think I could have made that clearer in the video (:
Why on Earth do you need linked list for such a game?? When Breakout game came out in 1976 nobody even dreamed about linked lists and yet - they managed to make such game.
There is a reason why C is still VERY popular and still the language of choice for creating Operating Systems and other low-level code (though Rust has become a viable alternative). That is what it was designed to do. But the creators of C never intended it to be the universal language. In fact, they didn't believe in a "universal programming language". They created a host of other languages for specific purposes, some narrow and some wide.
Yeah I was learning zig for highest performance generated assembly, but I've been drifting back to typescript for the comfort and ergonomics. Programming in assembly sounds like major lock-in to your hardware. I should really just be coding in c++ but I've got a huge contrairian streak.
Depends on the application, but a good performing application written in C/C++ probably isn't going to be portable, & it also dependent on the libraries used. For instance if your code used Windows libraries on a Linux or non windows machine, its not going to be portable. Portabile application are usually very limited or are slow if the use cross platform libraries for GUI, or OS specific functionality.
Yes, you're right but if you're using OS specific functionality there's no reason for it to be crossplatform. Like Java for example works everywhere because it makes it really hard to do platform specific things. Obviously you can always for example assume mounted sysfs and your windows build will fail at runtime no matter the language. What's good about C is that you can compile time branch the behaviour with preprocessor which effectively allows you to go crossplatform while using peculiarities of each supported platform. You have to design your application with the crossplatformness in mind from the getgo adding it later would be a pain in a large project.
I’ve never considered assembly hard, just tedious, like doing math on paper. Programming games in the 80s and 90s, we didn’t use any libraries so wrote all of the core engines in assembly - anything that needed to be as fast or small as possible.
I need to make a bread!: Assembly: alright lets go to the field and grow some crops, then lets make all the machines we need harvester, miller and trucks, and use them then we can make a bread, Ow and dont forget to make the oven too, and a house! C: okay there is your machines, and there is the field, grow some crops, harvest them then mill and make your bread using this oven. C++: here are your ingredients and there is the kitchen😁
So good to watch it, I wanted to really learn asm, but it's so hard, I do c and c++ for my university's sake but work with python. How much time did you need to master asm? And what do you think should I learn it for cyber security?
Regarding assembly, malloc, printing, etc. are implemented by the operating system as syscalls which are a special interrupt, 0x80 on linux. Also, you can easily use any C libraries by declaring externals and linking your object files with libraries you wish to use. It's funny you said you needed malloc to have linked lists since malloc is usually implemented as a linked list in memory. Did the assembly version try to write to the drive instead of the RAM? If you didn't want to use any external code, could've simply reserved a decent block of memory for your malloc implementation
I've been curious about the best way to implement graphics in assembly, and this video gave some great insight on the topic. Unfortunately, it also discouraged me from ever wanting to make anything in assembly. 😅
Want early access to new videos and some behind the scenes content? Consider becoming a channel member ruclips.net/channel/UCQvW_89l7f-hCMP1pzGm4xwjoin
This reminded me of the time a colleague thought he could rewrite his C code in assembly to get more performance, what he learnt at the end was that the C compiler optimisation was much better than his assembly coding skills.
yeah compiler nowadays are really smart though, normally when you write your C code and let the compiler optimizes it aggressively, then you compare to your asm code, it's just no competition
The optimisations in compilers are pretty crazy, I guarantee I’m not smarter than a compiler.
Every time someone finds a cool way to optimize assembly code, they just add that optimization to the compiler. Modern compilers are just effectively 20+ years of knowledge packed into one little box.
Yeah, there are only very rare circumstances in which you could get any speed gain by rewriting something in Assembly. See for example Lua vs LuaJIT, where LuaJIT's interpreter is written in Assembly in order to store some important state in the same registers while the interpreter is running, and to speed up the fetch-decode-execute loop as much as possible. No C compiler can do that kind of thing at the moment.
This is the kind of comment that I find very strange. I think that people just haven't thought through what can be optimized and what can't, but everytime that I _thought_ that I could out perform the compiler, I was correct. I don't feel like I can do any better most of the time, however.
This makes the fact that Roller Coaster Tycoon was written in Assembly even more mind blowing.
worth it, last I recall, he has made 30 million dollars from that game
Well, almost every console game of the 4th generation (SNES/Genesis era) and earlier was coded in assembly.
When atleast the person who programmed it has made a lot of money from it
I didn't know that. This is completely nuts.
Thankfully the creator got paid.
indeed but also note that pretty much every 8 bit and 16 bit game was programmed in assembly!
What makes compiler optimization so great is its not just a single bit of contributed ideas from a single person whose smart in the field of assembly, but its a collection of all the smartest techniques anyone could functionally think of to optimize your code, as a result the compiler is the culmination of every idea of almost every geniuses' demonstrably proven optimization technique, its basically the collective execution of every single engineering wizard in a singular binary who also knows exactly how to evaluate your code most efficiently almost all the time. (granted we assume all compilers do the same optimizations to low level machine code, which outside of edge cases and small processing differences that's pretty much true)
Very true!
I consider C/C++ compiler to be one if not greatest marvels of software engineering. It’s the culmination of thought of thousands people over decades.
I’m 59 and wrote my first program in an assembly type language in 1977. We are truly standing on the shoulders of giants. I am an aerospace engineer, but still need to write code to automate engineering tasks. Visual Studio is my environment of choice because it makes my job so simple.
Entering college for aerospace engineering next year & a total compeng nerd. I look up to you!
@@psltmtir one day you will be 59 and look back on a successful life and career. Make it a good one.
Visual Studio Code or Visual Studio ?
I recently switched from Notepad++ to Visual Studio (not Code). I am surprised how bad it is at basic tasks, like search and replace (it's slow and half the time doesn't replace or skips one replace). It also takes up 700MB in memory when running.
I'm impressed. My mom was an engineering aid working at the Boeing wind tunnel facility. She had the neatest pens for plotting out the results. She claimed she got sent to take Fortran classes because the engineers couldn't be bothered.
For his next trick, he writes it in transistors and binary
Binary (i.e. machine code) = assembly language, or, to put it another way, assembly language is a 1:1 version of machine code using opcode mnemonics. Crucial note: all opcode mnemonics are known during the CPU's final design stage - writing in 'machine code' = writing using the numeric values of these opcodes. Assembly language is, essentially, writing machine code using the human-readable mnemonic text version of opcodes.
No one writes in 'machine code' - it's all assembly, and always has been (on paper in the 'early days', with the machine code translated version along side ready to be loaded). Of course, an embedded system (e.g. space/satellite etc devices) will be pre-loaded with the 'assembled' (i.e. binary) version of a program.
For the next next trick he builds his own CPU from basic gates. No luxuries like MMU, I/O or DRAM. Need to write your own operating system.
For the next trick he writes the program literally on sand
@@ChrisM541 You know there's a thing called hexadecimal, right? And there are assembly pseudo-instructions, so it's not a perfect 1:1 map
@@ChrisM541”no one writes in machine code”
That’s weird, in my FPGA class everyone wrote in machine code. Except me because I wrote an assembler, but an assembler doesn’t always exist.
And even my simple assembler generated machine code that didn’t map 1:1 to assembly. You don’t know what you’re talking about.
He then made the same game in Unreal Engine and it was 140GB
You mean it was 140GB of assets... compressed somehow.
Exaggerated but still, my Asteroids and Defender clones came out at 140 MB each
Admittedly, it's been some time since I last considered programming in C a "breath of fresh air" over something else 😂
@_batman_Fan_ Honestly, I like it better than C++ now. So much more simple.
Not saying C++ is worse, but when appropriate, I would rather use C
C is not that bad, and strong emphasis: *in rare cases and applications* it's still the best choice
I can write something like this in C without ever looking at a line of doc or doing a Google search while I feel everything looks complicated in C++ and I spend a lot of time searching and doubting myself. The fact the author feels a class of library was helpful for this leaves me perplex as well... when all you need is a few structs and arrays.
honestly i prefer C over anything else any day, truly a breath of fresh air
The productivity boost moving from C to C++ is enormous if you understand the principles.
I’m taking an assembly class right now. Really makes you appreciate c++
I was thinking about learning assembly, thank you for changing my mind
It's still a fun challenge!
That's a shame. You're the one losing something so whatever.
Idk if you ever tried but you should learn it. There are many good lessons you can learn even in high level languages from doing some assembly
It's worth learning C and/or assembly, to better understand how computers work at a low level, and because C in particular is used everywhere. It's worth learning Python and Rust and Javascript, for their respective tasks. But it's probably not worth learning C++ any more. Other languages do its job better.
good video, short and straight to the point. Nice!
Thanks, that’s kind of the style I’m going for (:
i just took a look at your code and for some reason the assembly one looks way cleaner and simlper than the c++ one, at least for me. congrats on the readability of the asm version
Thanks for checking out the code, glad you found it legible.
Well to be fair when writing assembly you obviously want to write as little code as possible, so naturally it's going to be cleaner because less code = less chance for spaghetti to cook 😂
@@jlewwis1995 "spaghetti to cook" 😂
>Using a linked list to write a breakout clone
What is it with you modern, high level 'programmers' that feel the need to shoehorn random memory structures into your programs?
You can write breakout with just statically defined, bss memory - you can even use bits in a calculated grid system for the blocks to maximize cache utilization in the collision detection and make massive games that still run fine.
This is the thing about assembly that many people don't seem to understand: you control exactly how complex it is; you control exactly how much useless abstraction you add to your system.
It just so happens that simple solutions to simple problems are also usually much faster than complex solutions.
You are right, it was an active decision on my part to increase the complexity. I felt it told a better story of how each successive language made development easier by increasing abstraction, by having a common-ish design across all three. It also helped highlight how low-level and bare bones assembly is.
@@nathanbaggs Maybe so but it also failed to highlight one of the largest benefits of programming in such a low level, namely the direct incentive and ability to write said program in as few instructions/using as little memory as possible. You, in fact, directly contradicted it by exclusively focusing on its flaws. The whole point of programming in assembly, these days, is to write extremely tight code with (optionally) tight memory constraints. Being bare bones is both a good and a bad thing but I saw very little good. In fact I don't think I saw any at all.
It's quite one-dimensional, this analysis of assembly programming, and it comes off to me as forced, like you were trying to form the narrative to be only what you wanted it to be.
I'm not saying go full jargon but misleading your audience just to tell an appealing story is exclusively targeting the lowest common denominator and is degrading to the heuristic knowledge of people who don't spend their days programming in assembly.
Instead of forcing the use of linked lists in assembly, I'd go for different approaches, sometimes as simple as resw.
Yup there are always multiple solutions to problems. I wanted to implement something non-trivial in assembly, so opted for a dynamic memory structure.
You still code assembly faster than I do in python
Well that's kinda to be expected, assembly is compiled and one step from machine code and python is an inefficient interpreted language
@@handleneeds3charactersormore I think you're misunderstanding what op is saying and bringing up unrelated points to the comment at hand.
@@handleneeds3charactersormore He meant That he isn't able to finish writing up Python scripts in as short amount of time as the creator can in assembly
@@LevaniaMeyanothere's that one unwritten rule: whenever python is mentioned, the inefficiency of python must also be mentioned.
@@handleneeds3charactersormoreTell that to Java
As a programmer myself, I'm really impressed at your level of knowledge. Very entertaining too. Keep making videos :D
Trying to wrap my head around how confused you would have to be to implement a linked list in assembly, or why you'd implement an allocator for a small dataset with a static maximum length.
Nerd
Linked Lists are trash. Because CPUs are not optimized for such unpredictable operations.
I'd say an x64 processor has so many registers that you don't really need memory for a simple game like this. You can store 8x8 blocks in a single 64 bit register. Xy position in 8 bits each, direction in 8 bits and the bat in another 8 bit and maybe score in 16 bit all mapped into a single 64 bit register.
You'll need 'vram' at some point of course, the console in this case.
The fun thing of 8 bit home computers like msx, c64 and spectrums was you can write directly to the display buffer, make use of sprites, add some sound etc without having to do system calls, or just console calls the the bios/rom.
There are probably ways to access libraries from assembly to do syscalls but that's a whole different can of worms.
Bro I was just making breakout in JavaScript lol
Good luck!
In our class we made breakout in c++ with qt framework
A really useful challenge for me was taking something as simple as a linked list and go from Python to C++ to C and assembly. On the way i dropped a view things like C++ had a dynamic type and a static typed version. C and assembly only had static types. And i always used the the knowledge as well as the generated code from previous versions.
This challenge really lets you think about what you are actually doing with high level features.
Can’t be disagreed, when I first learnt assembly I fall in love with it, but as I go I was trying to build more complex stuff like floating point arithmetic, and visual stuff it just sucked , because I have to implement everything from the scratch.
Any event it’s amazing work you have done , thanks for sharing.❤❤
^ That's how I feel with C lol
Did somebody say Scratch????
@@v01d_r34l1ty big reveal when u come to C after assembly, though when I first used python, I realized C still scratch 😂😂😂
@@abz4852 scratch is my first name😅😅
@@abz4852 oh god, fuck that language
it's a very similar experience to what the original comment has described, but it's many orders of magnitude slower and _incredibly_ restrictive
I’m a bit lost as to why you would need linked lists for breakout. Breakout is a game that could be handled pretty easily using only the data segment to define your static array of bricks and player tokens. Biggest pain I foresee is the gameloop, graphics, and IO but none of that should require dynamic memory.
Sure it might be a bit over engineered, but I had a rough design that I wanted to implement three times - and that included a dynamic data structure. So maybe my phrasing wasn’t accurate, I didn’t “need” a linked list.
If I was making a “real” game definitely I’d think a bit more about what data structures I used (:
A 2d array would be better than using linked lists
@@AbAb-th5qei mean, at the assembly level you could do it with a big int. If a bit is a 1, there's a block there. If it's a zero, there's no block
@@amyshaw893 Yes of course. But it'll need an equivalent amount of bits either way. The only difference is how you interpet them. However, linked lists in this situation will make for more indirection, more work and more memory used. C doesn't have big ints AFAIK, but it does have character strings. These can be abused to do kinda pseudo big ints. Come to think of it, x86_64 asm doesn't have native big ints either right?
@@AbAb-th5qe wouldnt a 2d array need a full byte for each element? im not sure if you can make a 2d array of single bits, plus that doesnt include the array overhead
Wasn't disappointed with this video, great work.
I got a class this semester that specialises in the architecture of computing units. It's mainly aimed towards optimisation. Going from single thread unoptimised code to heavily multithreaded, optimised in all aspects, vectorisation, working with cache more effectively, reading less and what we need. Understanding how CPUs manage to do more per clock and how you can help it as a programmer with properly designed code. That's just something awesome.
But yeah, you're not gonna expand your for loop, let it read 4 different values behind each other, because it takes three clock ticks to actually get it and work with it, so your code would do nothing. That's just a small part the work compilers do for us and I personally think that is awesome. They are written by smarter, more experienced programmers and are in development for longer than I am alive. No point in drag racing them.
I got to say, had one class about assembly and I don't even know where I would start if I were to try to implement something in it, not to mention with GUI.
Great video showing that going deeper doesn't always mean faster. Can't wait for the next one titled "I tried to write something in binary by hitting neutrinos with my HDD (just kidding, used Emacs plugin)"
Thanks! Glad you enjoyed it
Sounds a lot like the legendary APS class at CTU FIT
@@ChipterLP You're remarkably close. But it's AVS class at BUT FIT :D
Great video, this is the kind of stuff I work with daily. How come you keep implementing linked lists? Would a normal array not work fine here? Linked lists are often more trouble than they are worth because of the memory overhead in each element and it is comparatively much more computationally expensive than a typical array.
I went for simplicity over efficiency. I didn’t have to worry about bounds checking, resizing and copying elements (for dynamic array). Just allocate a node and wire up the pointer!
@@nathanbaggs there’s a realloc function on the c standard library that does the reallocation and copy (if necessary) in one go.
yeah: in ASM the only structure is array (possibly of records). You do not need memory management in ASM. You work on your own private array statically allocated with your program.
You can also implement a linked list in an array. One node could have the array index of the next node.
@@drivers99 yes sure, index is just a local pointer relative to the array. But higher level structure aren't natural in ASM. Better use data structures better suited to your language. Low-level langage imply low-level data structure.
One thing you did in your code that I've never thought about doing is writing out the function logic as a comment block under each prototype on the header file. I could see how useful that would be for other devs who don't want to drive into the specifics of every function, only what they do and return in an abstracted way.
Glad you found it useful, I'm a sucker for writing code documentation (:
@@nathanbaggs well, you'd be called a sucker for that because they stopped teaching the importance of documentation, as far as I know, in the last 10-15 years, because people whined about having to show their work.
cool video, its make me want to learn again about low level and assembly deeper
Despite not writing in it since college when i used these little embedded project boards, i think my experience with assembly is invaluable. It allowed me to better understand how things work under the hood when programming in higher level languages, like C and C++. I would love to program in assembly, but it is way too tedious to do so for the code i write. We should be thankful to the creators of higher level languages who abstracted away the tedium of assembly and made programming much less tedious. Great video, btw!
you guys wanna REALLY have your minds blown?
nearly all 8-bit and 16-bit games were designed in assembly
let THAT sink in
Entirety of Roller Coaster Tycoon was made in assembly. Let THAT sink in!
Let the sink in already he's cold.
Love the bit about "the assembly can only be as good as i can write it"
A lot of people seem to think that writing in asm is racing stripes to make the computer go faster.
Humans should do the things humans are good at and leave the things computers are good at to computers.
In the past using inline assemble did help when compilers didn't have the optimization they now have. In some instances a significant performance gains could be done. Usually instead of writing an entire application in assembly you wrote a few specific functions that are imported into C/C++.
but assembly was made for humans to write. it's what the intel manuals for x86 programming cover. people have, and continue to write faster assembly than a compiler. usually because of them making use of certain instructions that the compiler doesnt.
@@minneelyyyy So were punch cards. I don't see anyone stumping for that.
As far as a human beating a compiler, maybe on a single function or optimizing work the compiler has already done, but toe-to-toe, human vs machine the machine will win every time on any non-trivial program.
i'll bet my lunch money on that.
@@khatdubell punch cards are a funny example considering that no modern computer can even understand them, thats very clearly an old technology. assembly, however, is often benefitial in small amounts. it is necessary, too, for things like osdev or writing low level code for the os.
@@minneelyyyy Compilers will used advanced instructions. It really depends on setting the compiler settings. About 25 year ago C compilers defaulted to the 386 or 486 instruction set, and if you wanted to use the extended instructions of i486, Xeon, you had to enable the compiler setting. The issue with using extended instructions was that a lot of machines had processors that didn't support the extended instructions. I believe today compilers all have the extended instruction sets enabled.
i like the way he is so on point.
Thanks, my goal was to keep it succinct.
Well if you code in assembly with a c++ mindset no surprise you'll find c++ more comfortable. Same happens if you come from python to c++. Not to care about pointers and memory allocations is a "breath of fresh air" in python after c++. However if you do care about efficiency you'll find python frustrating, since you can't controll what the computer is actually doing. So if you learn the c++ mindset you'll find python extremely limiting. The same applies to assembly: if you wanna squize the last bit of performance out of the computer you'll find c or c++ limiting after assembly. Of course it doesn't really apply to moder PCs but could be a real issue with programing microcontrollers, 8 bit retro computers or other devices with limited resources.
Yeah for one thing I was like why TF do you need a linked list for a breakout game??? For the assembly part you could just do what people do for retro PCs and just take a big chunk of heap memory and slice it up into a memory map for the game to use with pointers for each part, one part of the memory can be for the ball, one part for the bricks, etc, there's no need for a linked list or any sort of fancy data structure like that for this simple type of game...
Inline assembly left the chat
use assembly to programming with ZX Spectrum
hey man, first, congrats on making something that complex in assembly without years of experience in it! I feel like you took a very wrong approach to coding in it and C though. The first realization should have been that you don't need a linked list, or a malloc, you need only do the steps required to run the game, just mapping a few memory pages and getting a pointer to the window vram from the kernel is all you should really need (as well as communication messages between the os and you but you had to do that regardless).
Ofcourse working without the niceities is tough if you've never done it before so it seems like the only thing to do in x86 assembly is to look at it and start your IDE with a normal language on it, but there are still very good uses for assembly programming, though not directly in assembly. What is done (most commonly in the games industry because that's one of the last places where getting everything out of your computer matters) is you take a very unoptimized problem, you shrink it down through regular optimization, and then you apply SIMD to it. What's that? Yeah there are special assembly instructions a C compiler will never use, unless you tell it to, and even then unless you structure your data right, it won't get to use them. These instructions can process whole arrays of numbers or even matricies of numbers at once, there are instructions for ray intersections, for regex filtering text 16 letters at a time, cryptographic functions, all these can be done by specialized wiring inside the cpu extremely more efficiently then any high level code could. And that's mostly the only place assembly should be used, because as you've discovered, it's a pain. Thanks for sharing it with us!
I might have over engineered the assembly design a bit, which has been pointed out in a few other comments. But I wanted to see how easy it was to create comparable solutions across the three languages, which includes dynamic memory allocations.
I wouldn’t consider myself an assembly expert but I’ve read/written enough to get by. So I’m familiar with SIMD, etc.
Reminds me of the guy who programmed an entire roller coasters game in assembly.
I thought I knew how to code a little at least, and then I watched this video lol! You’re a genius
I’m glad you enjoyed the video! I certainly don’t consider myself that, it’s just hard work and practice, good luck on your journey
You are such a legend, well done.
Thanks! Glad you enjoyed it
1:09
about malloc
you can use C library functions in assembly program perfectly well
you just need to take care of the ABI
A valid point but I wanted to try without libc and just use syscalls
@@nathanbaggs oh
alright then
great video
very inspiring
makes me want to start my own project
All this is way over my head, I used C in the past but that was in the eighties running on SCO Xenix.
But I do remember the code for this same game written in the Basic that came with the first gen Apple 2, I doubt if it was much longer than 30 lines due to the graphics and paddle capabilities that Woz built in when he wrote the language. It ran seamlessly on a 1Mhz CPU with the 32k Ram I started out with.
Why would you need malloc to code a version of Breakout in assembler? Surely everything would just be statically allocated and you don't need anything more than simple arrays to represent the set of bricks on the screen (e.g. 1 byte per brick with each brick within a grid: 14 column x 8 rows). An early assembly programmer wouldn't even do that, they'd allocate 1 bit per brick. Then you'd first check the location of the ball: ball_y>=brickmap_y; && ball_y
I think I could have been more explicit with my choice of words, I certainly don’t “need” malloc. I had a rough design that I wanted to implement three times and that included something non-trivial like a dynamic data structure.
Thought it was gonna be one of those nonsense "writing the same game, using the same source code-ish to see the difference between C and C++" but the fact that you actually leveraged what C++ does so great (like RAII), anonymous namespaces, etc, makes it rather refreshing.
Glad you enjoyed it! I’ve been a C++ developer most of my career, so it’s the language I know the best
You didn't need a linked list (an array is plenty for your game) and you didn't need to implement x11 directly. C doesn't provide graphics libraries any more than assembler does so if you allow yourself to link libs in c then you can allow yourself to link them in assembler.
Yeah, I created a similar game in assembly and didn't use any exotic data structure
some of these still rely on libc because of the initialization code. if he was on windows he could use GDI of course
Much work you did here, but very interesting. Thank you!
Come on, you can use any C/C++ libraries with assembly too. Maybe it's not very easy, but coding in assembly doesn't have to mean coding every single part of the code in assembly. For me the most effective way to code something like a game is mix various languages. Where you need high complexity - high level languages, high performance - C++, C, assembly. I found C# is like perfect for some complex (or dynamic) data structures, high-level protocols handling, but it's not good to just push bits from one place to another with consistent timing. C is perfect for pushing bits reliably, but handling complex things with it gets tedious. C++ is something in between. The speed of C, but it's a little easier to add some more complexity without writing too much. BTW, C flavored C++ is a cool thing. You just use C++ like C with namespaces ;) That approach works surprisingly well in some scenarios.
I'm curious why you implemented malloc for the x86 version? I've done some simple games targeting wasm without libc and had no issue just putting everything into a statically allocated buffer
You’re absolutely right I could have done that. I wanted to try and keep the three implementations similar - C and C++ used dynamic allocation so I wanted to see what it would take to do that in x86.
@@nathanbaggs Conceptually I understand, but as a counterpoint you have programmed in C like a C programmer, in C++ like a C++ programmer, and in x86 like a C and C++ programmer. You've made a good video. I was expecting to see a comparison of programming languages paradigms, and didn't find that.
@@PhilipBarton He also could have put everything into a statically allocated buffer in C and c++.
Its not "thinking like a C programmer" to dynamically allocate memory. Its part of writing more than a basic program.
@@khatdubell the simple approach is often the best one, a "basic program" is what you should aim for.
If there is no need for dynamic allocation, doing it just makes you code objectively worse.
@@marcossidoruk8033 only using static allocation isn't a solution tho.
It still makes things complicated, because you need to separate it into chunks. Same thing with dynamic allocation, using mmap gives you a page of memory (so 4096 bites) that you need to cut into chunks. You could very well just ask mmap for way more memory memory a single allocation and then do your thing. At the end of the day, mmap will return you consecutive memory because of the layer of kernel abstraction around memory.
Always remember the costs associated with the coding and maintenance of the code. But that is part of losing knowledge, people are forgetting the basics learned from the 1960s through 2000.
Great video again!
OUTSTANDING video. Thanks so much.
And then there's Tom who worte Rollercoaster Tycoon entirely in ASM. Wild.
This is why we did design before coding in those days. That's still a good practise, even when you use C++.😉
In the '80's it was easy to write apps in Assembly that were faster than C. Since then the microcode in microprocessors got far more sophisticated. The longer pipelines & similar sophistication are things that compiler writers spent a lot of time optimising their output to take advantage of. But you have to think of all that with you are also dealing with the logic of your code. Thats tough.
In assembly you have access to all the standard Microsoft libraries and with a decent Macro Assembler like FASM, you have macros to handle those function calls. Moreover something like tail call optimization is usually just a jmp call in assembly, while impossible in C, unless the compiler provides it.
Some of those macros are pretty powerful and you can actually be productive in assembly. The main problem is that it's not portable.
I found this video extremely useful Nathan, thank you.
I had to put a SDL_Delay(1) statement in the running loop as it was impossibly fast to play, and cpu usage was very high - unless I did something wrong?
I also had a compiler warning in c_window_destroy line 79. “Potentially uninitialised variable” - fair enough! I commented this line out for expediency.
The hardest part of this was installing the SDL lib. I was stupidly trying to build a Win32 using the 64 bit SDL lib - silly me!
If you do not give CPU time explicitly in an infinite loop (for instance by SDL_Delay(1) or any other "sleep" function), CPU will be consumed with 100% (at least on one core), as task scheduler will always give immediate control to your application (unless there are other applications which are in active state and have prio equal or higher than your application).
No idea why you'd need a linked list to implement Breakout.
Every time the ball hits a brick you have to append a 1 to a linked list, this is necessity for Breakout. Otherwise, you can't really call it Breakout.
Wow this is awesome! Somehow you're so much underrated, anyway, I subbed.
Glad you enjoyed it!
First of all probs for this cool interesting video.
Secondly I need that theme xd
Glad you enjoyed it, the theme is Dracula
@@nathanbaggs Are you using the normal, or the Soft one?
i wrote a thing like this way back in Turbo Pascal, fun fact the pascal compiler was written in assembler, still amazes me to this day!
The asm version appears to run slower than C/C++ versions. That says alot about compiler optimization. I would try turning off optimization, compiling and running to see if that makes a difference
More likely, it says things about data structures or algorithms build into C/C++ libraries. If it was code for code, compiler optimizations on a game like this would be minor.
30 years ago I was writing games in x86 assembly. I was 18 at the time and it was exciting to have a level of performance that I'd never been able to achieve with stock libraries that came with my BASIC and C compilers. But... yeah, that's a lot of extra work. I very quickly switched to writing my own graphics libraries in assembly and writing everything else in C. Kids today have it too easy. I could rewrite that entire project in C# in a weekend.
I would love to see an in depth video on the x86 version
You can use libraries and call functions in ASM. If I'd
been writing in ASM, I'd have used SDL and libc. Just because you're writing in one language doesn't mean you can't call functions written in a different language.
Many thanks aks for sharing your AMAZING project 👏👏👏🔥✌
Please consider making end-to-end tutorials for the whole project. 🙏
That will be extremely helpful for c cpp assemly learners.
Maybe more similar projects in the future
Many thanks in advance! 👍
Glad you enjoyed it. I’d like to try out some tutorial content in the future
Why would you need a malloc and a linked list for a simple breakout ? You only need a fixed amount of memory to store the level and the graphics. Just use data and bss sections. Anyway I never coded in assembly on Windows but I'm pretty sure there are Windows functions to allocate memory dynamically.
You’re right, you don’t need it, I think I could have been a bit more explicit with my choice of words. Also something I could have been clearer on is that this was written using WSL, so it’s all Linux syscalls.
Thanks for the video, waiting for more like this video with othe programming languages
Assembly is my main programming language as a ROM hacker and reverse engineer.
Long Live Assembly! 👍👍👍
When I was a student, I also made this game in x86 assembly, what a nightmare in 2002... no internet.
Why would you choose to use a linked list as your default container? Dynamic arrays are simpler and more efficient in most cases.
I wanted to implement a simple data structure and for me linked list is easier to implement if you want to remove from the middle of the container.
I appreciate an array is more cache friendly and more efficient for iteration.
@@nathanbaggs that's reasonable, thanks for the reply
It's funny that lots of early games, especially consoles, utilized assembly because no one had the budget to make a whole custom C compiler for their hardware with very specific features. Even as C finally started taking over, inline assembly was still common.
Unless you were working on some big UNIX machines, you had to use assembly for the performance because there just wasn't an optimizing compiler available.
GCC was a game changer when it released.
insightful experience. You should try to that similarly using Rust, it's not very different from C++ (you might need to "let go" some C/C++ concepts) but it's interesting language (kinda boring also, but the safety is worth it).
The amount of people in the comments mentioning rust was not unexpected. It’s on my todo list to learn, I want to spend some time with it before I can do a fair comparison
@@nathanbaggs That's the best approach to Rust imo. You'll see why once you learn it ;). The official docs are great also
That is very useful and impressive. Thank you.
man im so glad you getting recognition, keep it up
Thanks (:
Okay, I have to ask, why did you have use malloc in ASM? It sounds like you litterly reinvented the wheel, because of your familiarity with how you are used to doing things.
Having coded in all 3 languages myself here is what I can say. Don't expect any hand holding in ASM, if you're doing things the same way you did it in a compiled language you're probably doing it wrong.
Examples are, coding while using a compile anywhere mentality. ASM by definition is machine specific. Your targeting specific hardware, using a specific OS. Once you realize this you will find in every OS a specialized memory management API. You then have to think how that API is meant to be used. Then make it do what you want.
At my peak I got to 50/50 when comparing my code to compilers. Half the time I could beat them in both size and execution speed. It only got better if I peaked at their output and used that to optimize mine. You probably have no idea how often compilers tend to add a ton of unessarry stack management. If your good you can manage your entire stack with math and free up your stack frame register to be used as a generic register.
C is the baseline I compare all languages against. Its simple no nonesese calls and structure generally makes this one of the simpler languages to work with.
C++ is what I use when I need lots of easy to implement data structures. Of the 3 languages this is the one where data management takes the foreground. This might be a bit overkill for a breakout game. As most of your data structures are ideally just arrays.
So if I were to equate the languages as tools to move boxes. ASM is using tweasers, C is just picking them up manually, and C++ is the forklift. And don't get me started on what you can do when you realize you can export libraries in c and c++ to be used with ASM, and you can use inline ASM in both C and C++. These languages are litterly interchangeable.
You don't need linked lists. You have a memory buffer containing the bricks, you need one bit to activate or disable a brick
This seems to be out of the scope of the video but I'd be curious to see some sort of performance benchmarks in terms of FPS comparison between all of them! Would be cool to see how little or much the pain of low-level programming is for speed.
Language won’t give you any speed benefits considering today’s optimizations within the compiler. Listen to Lex Fridman podcast with Bjarne Stroustrup and he talks about this.
@@jorgeherrera1074 Depends on your compiler, really. For Arm, Intel, Power, SPARC, etc. there's rarely any chance you'll outperform the C compiler. Some lesser-used architectures don't have any good C compilers (or charge a fortune for them), so there are still places where hand optimization is useful.
PIC comes to mind here - I don't know how it is now, but back in the day the only free compilers available weren't very good. You could pay for better ones, but it wasn't cheap for a hobbyist. I suspect that's a major reason the ATMega got used for Arduino over the PIC, which was more common in the industry.
@@jorgeherrera1074 Good to know this is generally the case and thanks for the reference. I'll check out the podcast!
and @@jeffspaulding9834 also very good to know that this is not always the case. I'm curious to know what hardware has unoptimized compilers. I rarely write embedded software so hopefully I should be safe using the C compiler most of the time!
@@bren007pie2 PIC is the biggie - if you don't pay for Microchip's compilers, you're stuck with unoptimized code.
I looked around and things seem to be improving. Lots more microcontrollers have gcc or clang support these days. Some manufacturers still recommend commercial compilers, but gcc seems to be gaining a lot of traction.
100th like keep it up bro awsome content
i might be the old one here but i remember writing a breakout game in ASM and i had no issues with memory to get more banks or issues with the data as i could get away using the video memory instead of an array of blocks. and a counter to know if we ran out of blocks.
and it was running just fine - sure there was no windows / gnome (x) to worry about as it was dos based, but if anything it was TOO fast, so had to slow down the bounce to whatever millisec to be playable.
(of course C compilers are making much more effecient compiles, but it does not make a difference at such a low complexity game and where you have to slow it down anyway)
and we are talking about 8MHZ cpu speed and not 4.2GHZ with 16 cores :)
i agree writing the code is easier on higher level languages, but i reject that there is no fun and excitement working in ASM. at least for me it was fun
True. What is hard to see here is the fact that writing in such a low level language as assembler in such a high level operating system feels very obsolete. I also think I sound like the old one here, but when you have nothing but a blazing fast 20 mhz machine and a brand new, 1000$ EGA graphics card, you'd LOVE this low level ability to manipulate any register to your likings, twitching and twisting the bits around, just for this one, little more of speed you MIGHT get out of it. It's like playing with lego blocks, a craft with a very hand made feeling to it.
I think I could have made myself clearer in the video. Instead of “I needed a linked list” I should have said “I wanted to write a linked list” - and the reason for that is I felt it told a better story of how each successive language made development easier.
As you and others have pointed out, there are alternative/simpler ways of storing data.
@@nathanbaggs Don't get me (us) wrong we are not here to fight or lecture you :) the mere fact that someone is still attempting to do ASM is great :)
But on one thing we are going to disagree :)
Actually your attempt did not show the real picture of how each language made development easier.
See forcing linked list on ASM is something absolutely not language 'correct'
I would say using the standard ways of storing data would have showed how different and what benefits the new languages are bringing. I mean once you had your linked list library, its frankly no different on the surface than calling some high level functions in C / C++ since now you HAVE it thanks to your library.
What your approach showed that ASM is capable of having whatever a high level language has, but it does not show the real progress.
i mean this is a good example:
call cls
jmp $
cls:
pusha
mov ah, 0x00
mov al, 0x03 ; text mode 80x25 16 colours
int 0x10
popa
ret
(copied from stackoverflow for easier reference)
this is what you did with the linked lists. :)
But now there is no difference between invoking a high level CLS or this here... So in fact you blurred the boundaries :)
i think what would have made more sense is to show how you get data in and out from say the graphics card memory to handle collision detection and then show how much easier it is to use an array or a linked list.
the same would go for keyboard handling, or writing text on the screen... etc :)
anyway, it is a good video, so keep up the good work :) you are onto something here and i am sure great success is ahead of you :)
@@luicecifer I agree, coding in assembly in the day and age when you have layers upon layers between you and the hardware is obsolete for "everyday coding".
but it has the benefit of learning how actually the CPU is working under those layers. it might help someone to think when they write their highlevel code. (lets talk about the predictions the CPU makes and calculates ahead just to throw away everything it failed with the predictions - IF statement in a loop for example)
For non everyday coding however where every cycle counts assembly is the best friend besides C / C++. (when maybe a millisecond decides between a disaster and a successful landing on Mars - and you can't afford running a multilayered system for limiting errors and resource eating) :)
:) and ASM is such a highlevel coding compared to punchcards anyway :D :D
Thanks for the feedback, I can only make the next video better (:
There is a mindset for each programming language. Similar to how a spoken language has depth of expression with more experience.
Yes, I like the phrase “idiomatic usage”
This looks like a C++ programmers investigation of what it takes to implement their high-level language features in lower level environments. Which is fine. But I think it misses an opportunity to investigate the different approaches to problem solving that are appropriate for those lower-level languages. Why use dynamic linked-lists in assembly or C? Just allocate static arrays of data. What's the difference is implementing graphics (quite hard in assembler, would have loved to see how you managed that).
You lament the lack of fancy data structures in assembler, but really, you don't need them for something like this. With assembler, you can write breakout that runs on an Atari 2600. You can't (easily) do that with C++ (without a modern computer capable of very fancy compilation and very new C++ compilers).
It would be worth considering the advantages and tradeoffs of each level of abstraction. There's a reason the linux kernel is (mostly) written in C, not C++. It would also be really interesting to see a comparison to more modern high-level languages like Rust and Go.
I think that’s a fair point, I certainly started off with a high-level design that I wanted to implant three times.
You’re making a breakout game.
Why the fuck do you need a link list, dynamic memory allocation or exceptions?
Because he obviously programmed it from top to bottom then studied the converted C and compiled assembly code in order to make this video. His C code smells of a poorly done conversion from C++, and NO ONE who understands assembly would ever even dream of using linked lists the way he did.
While C/C++ compiler optimizations are usually faster than normal assembly code, note that optimized assembly code will be faster than C/C++ compiler optimizations.
The advantage of assembly code is that you only write the code that is needed and the assembler turns mnemonics into machine executable instructions. Higher languages rely on libraries which are general purpose, parameterised routines that include a lot more code. Then libraries are written that rely on the inclusion of other libraries... Yes, it makes the coding easier (read "achievable"), but less efficient. Hence we need super-powerful 64 bit cpus and super fast memory just to present a desk top.
I taught myself z80 and 6502 code in the '80s and progressed through a career in COBOL and similar 3rd gen languages in the '90s and '00s. I haven't written code in decades. But the fact remains that the nearer you get to the metal the more "immediate" the execution becomes. However, trade that off against the difficulties of coding at that low level (the Roller Coaster Tycoon that others have discussed). But you can write crappy inefficient code in any language, so speed of execution isn't just a property of the language. The driver behind current languages is speed to market, not speed of execution.
As someone who started to learn programming on ZX with 48KB I have no idea why you needed the linked list. I have a feeling you coded in assembly as if it was C++.
Breakout doesn't need linked list, malloc or free. All data is statically known. Bricks can be handled using a static array(which is so small, it can live in stack), removing a brick can be done in a way similar to erase/remove idiom (swap N-th with the last, then pop). Maybe X11 needs something special, but then again - why did you use X11 and not SDL like with C/C++?
I'm not fan of asm, especially when now instructions look like you roll your head over your keyboard(PCLMULLQHQDQ), but I feel at least half of the struggles were caused by overengineering a program.
That’s a fair point and one that a few people have mentioned. I wanted to compare the three languages, including using/implementing data structures - and I figured linked list was easiest to implement. In a “real” game I’d think a bit more carefully about the choice of data structure. I think I could have made that clearer in the video (:
I agree it is a bit over engineered, but that was almost by design
Nice video, why is the framerate so bad though?
The assembly frame rate is bad because it was a really basic game loop. For C and C++ I’m not sure why, I didn’t notice till after I the rendered video. I think it might be an issue with how I recorded it, lesson learned for the next video (:
@@nathanbaggs no hate meant, still one of the better videos i've seen this year :)
@@nathanbaggs have you been runing in debugging mode, apparently that slows things down a lot
@@nathanbaggs really basic game loop, written in raw assembly, running on a super computer = bad frame rate?
@@stephenkamenar yeah that doesn't quite add up lol, even if the code was really bad I doubt the fps would be as bad as it is in the video, then again they did think it was a great idea to have a linked list for something as simple as a breakout clone that doesn't really need something like that in the first place so who knows, maybe there's some other unnecessary thing in that "simple game loop' that's causing it though I couldn't really imagine what 😂
To all those who extoll the virtues of compiler optimization - yes, it does a lot, but if you're doing any kind of SIMD or MIMD favourable maths, you can seldom beat hand coded assembly, even if you've qualified every line and used aligned memory. Even intrinsics don't always cut the mustard, but they can get you a long way.
Damn I thought you had like 200k subs or even more judging by the qualities of your videos.
You have earned your self a new sub
Ps could you make tutorials for c++ :(
Thanks for the kind words! I've been considering making some tutorial content, do you have any specific part of C++ in mind you would like tutorials on?
For such a simple project i'm not sure why you'd need dynamic allocation nor linked lists. Given that all levels are statically allocated on a fixed size grid.
You’re right I could have simplified it. I started off with a rough design which I wanted to implement three times, and that included something non-trivial like a dynamic data structure. It was fun seeing how each successive technology made development easier.
Not me sitting here struggeling over my assignement for "Introductory to programming" class in uni using C and this guy goes. "C was a breath of fresh air". Pointers and structs have become the bane of my existence
Keep going! It all makes sense with practice, I was where you are now when I was at uni
Yeah pointers are an odd concept to begin with but the best advice (or at least what helped with me) was to just write some code using them, simple data structures like a stack or a linked list are great for learning and getting your head around them. If you can't start there, look at some existing data structures and mess about with them. I've learnt everything I know from doing rather than reading. It just takes time and practice. One day it will just click and start making sense. I didn't think I would get my head around C but I did, I didn't think I could write anything in ASM but I have and I certainly never believed I could write my own language from scratch but eventually that was ticked off my list too. If you want something badly enough you can make it happen, I'm sure you will too.
If you approached the asm with an old school mindset you would have simply skipped the malloc and linked list for a project this simple. Neither would be necessary. In simple systems we used and reused static buffers defined in the assembly directly, and linked lists if used at all were usually using embedded pointers in the statically allocated objects. Though right enough larger systems typically ended up writing much of the same code a C runtime includes. FWIW once the C compilers evolved enough to generated decent code, everyone, barring a few stick in the muds, switched to using C with asm used only to enhance performance where it was most needed.
Wow, did not know about std::optional, that's awesome!
It was introduced in C++17 and was a real game changer for me in terms of API design. No need to bother with out parameters. It combines nicely with if statement initialisers, so you can do:
if (const auto v = func_returning_optional() ; v)
{
}
Petition to release a full detailed video like a tutorial
I’d like to try a tutorial video, any ideas what you would find useful?
@@nathanbaggs Any C, C++ or Assem based projects and you could walk us through step by step would be really helpful
why would you use a linked list instead of a simple grid array and a 'remaining walls' counter? It's much easier to implement, faster, more memory efficient and doesn't require any mallocs
That’s a fair question and one that a few people have asked. I wanted to compare the three languages, including using/implementing data structures - and I figured linked list was easiest to implement. In a “real” game I’d think a bit more carefully about the choice of data structure. I think I could have made that clearer in the video (:
Why on Earth do you need linked list for such a game?? When Breakout game came out in 1976 nobody even dreamed about linked lists and yet - they managed to make such game.
What did you use a LL in a breakout game for?
There is a reason why C is still VERY popular and still the language of choice for creating Operating Systems and other low-level code (though Rust has become a viable alternative). That is what it was designed to do.
But the creators of C never intended it to be the universal language. In fact, they didn't believe in a "universal programming language". They created a host of other languages for specific purposes, some narrow and some wide.
Yeah I was learning zig for highest performance generated assembly, but I've been drifting back to typescript for the comfort and ergonomics. Programming in assembly sounds like major lock-in to your hardware. I should really just be coding in c++ but I've got a huge contrairian streak.
Depends on the application, but a good performing application written in C/C++ probably isn't going to be portable, & it also dependent on the libraries used. For instance if your code used Windows libraries on a Linux or non windows machine, its not going to be portable. Portabile application are usually very limited or are slow if the use cross platform libraries for GUI, or OS specific functionality.
Yes, you're right but if you're using OS specific functionality there's no reason for it to be crossplatform. Like Java for example works everywhere because it makes it really hard to do platform specific things. Obviously you can always for example assume mounted sysfs and your windows build will fail at runtime no matter the language. What's good about C is that you can compile time branch the behaviour with preprocessor which effectively allows you to go crossplatform while using peculiarities of each supported platform. You have to design your application with the crossplatformness in mind from the getgo adding it later would be a pain in a large project.
I’ve never considered assembly hard, just tedious, like doing math on paper. Programming games in the 80s and 90s, we didn’t use any libraries so wrote all of the core engines in assembly - anything that needed to be as fast or small as possible.
I need to make a bread!:
Assembly: alright lets go to the field and grow some crops, then lets make all the machines we need harvester, miller and trucks, and use them then we can make a bread, Ow and dont forget to make the oven too, and a house!
C: okay there is your machines, and there is the field, grow some crops, harvest them then mill and make your bread using this oven.
C++: here are your ingredients and there is the kitchen😁
“Stops @ 4:20” subbed
So good to watch it, I wanted to really learn asm, but it's so hard, I do c and c++ for my university's sake but work with python. How much time did you need to master asm? And what do you think should I learn it for cyber security?
In my uni we learn assembly in the first semester lol. Many people dont even know how to code yet.
@@theforeskinsnatcher373 what uni?
I am by no means a master, just know enough to get by.
@@theforeskinsnatcher373 that's a ordinary thing, just focus on yourself ✊
@@nathanbaggs Oh, I see, still big respect!!!
Regarding assembly, malloc, printing, etc. are implemented by the operating system as syscalls which are a special interrupt, 0x80 on linux. Also, you can easily use any C libraries by declaring externals and linking your object files with libraries you wish to use. It's funny you said you needed malloc to have linked lists since malloc is usually implemented as a linked list in memory. Did the assembly version try to write to the drive instead of the RAM? If you didn't want to use any external code, could've simply reserved a decent block of memory for your malloc implementation
malloc is usually in libc or another userspace library, not the kernel
@@mothcompute True, without linking to libc, mmap or brk would have to be used, which are exposed by the kernel.
@@zin_the_one fair
Cool video! Just a quick FYI: std:: vector is not a linked list
I've been curious about the best way to implement graphics in assembly, and this video gave some great insight on the topic. Unfortunately, it also discouraged me from ever wanting to make anything in assembly. 😅
Glad it was helpful! For me programming in assembly was more for the challenge, but don't give up!
@@nathanbaggs Yes it is quite a good way to challenge yourself. And it's definitely a good way to get more familiar with hardware too.
Look up what a bitmap is. Also there is a really nice mips assembly emulator that helps when learning assembly by the name of mars
You can use the same libraries you use in C/C++. Just that you have to be aware of calling conventions when calling library functions.
It reminds us why the original Elite was mind glowingly incredible.
(obviously that should be blowingly - the edit feature isn't working for me)