I made an entire OS that only runs Tetris

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments

A Finn named Torvalds once created an OS to run a serial port and a terminal emulator on an i386. It got big later, though.

👍︎︎ 6 👤︎︎ u/pdp10 📅︎︎ Apr 19 2021 🗫︎ replies
Captions
so remember back to my first video where i said that i was too cool for 3d engines or languages classes and garbage collection name spaces and things you don't really need yeah well i've thought some more about it since then and you know i've humbled a bit and decided i'm just too good for operating systems at this point too my beautifully handcrafted artisan code she'll only grace the cpu if it's supported entirely by my own software so naturally i've made an entire operating system but just to run tetris [Music] and yeah i know what you're probably thinking here isn't this the guy subscribed to because he's making video games well yeah but honestly when i came up with the idea for this project i just kind of had to throw my main one on the back burner because this was too good to wait and just as a little preface for this video it would be hours long if i tried to go into depth on absolutely everything so i'll link some resources down in the description if you want to learn more but with that other way let's get to it [Music] now normally i would start off by cracking open my ide slapping down a printf hello world compiling and running to test that everything works but without an os to even start with we're kind of in the wild west of computing here no operating system nothing that can load an executable file actually the only thing we have is the bias or the preloaded software that the computer runs at the start which will get us up and running to the bare minimum and not even that will let us start tetris or anything that complex first thing we really need to write is called the bootloader a bootloader is the first thing sort of in your control that's run on your computer as it starts up it's basically like a preloader for any operating systems and in our case the first part of it lives on the first 512 bytes or first sector of the hard disk the first place the bios will look for things to run once it's done its thing and is trying to hand over control to an operating system so to get started with our bootloader i just threw some assembly down into a file it will basically just pause the system when it loaded and tried to build it and tried again and again and tried again a few more times and then i considered briefly giving up this project in its earliest stage and finally after a few hours of troubleshooting i was finally able to get gcc to graciously accept my assembly file and have it spit out a binary to get our emulator we'll be using though to actually run this code we need to create a disk image for it to use as though we're a real hard disk this is pretty simple and with some basic shell commands we can write a couple hundred megabytes of zeros into a file and then use the same command to take our boot loader exactly 512 bytes in size and toss it right at the start oh and we marked it as bootable as well by putting these special bytes hex aa55 here so the bias knows that the disk is bootable and it can run code off the first sector so after that prepare for magic we can boot up qmu for the first time with our hard disk and it stops cool right almost done with the video at this point next step is to see if we can actually do anything productive which is to say literally anything at all so we kind of need to do the bare metal hello world equivalent and write something to the screen to do this we'll rely on something called an interrupt which is sort of a way of calling into code that in this case the bias is already set up for us before it even loads the bootloader almost like a prehistoric system call with a defined api and everything and luckily for us if we use interrupt hex 10 with register ah set to hex e it will print whatever character we throw in al to the screen and since hello world is maybe a little overdone i think i christened our bootloader by getting it to print tetris time in all caps perfect so now that we know our goat is actually running what's next well i'm sure it's all not going to write this entire thing in assembly so first priority is to get some c running in here but unfortunately that really complicates things remember how the bias has only loaded the first 512 bytes of what we put on our disk yeah the rest are up to us so if we want more than 512 bytes of code which i think tetris will probably take we're gonna need to get more sectors off of the disk containing the rest of our program so again here thankfully we don't actually need to interface with the disk directly and we can use a different bios interrupt to get a few more sectors after our first one loaded off the disk which is where we're gonna put the code that actually manages everything and runs the game so you can see me in the background setting that up here oh yeah yeah wait pause that you see that line there yeah that one that one where i typed hex 20 yeah that's a that's a major mistake but but i don't know it yet it's just one of those nice bugs that doesn't manifest until you know like hours later into the project when you have no clue why the hell your code isn't working so the cool thing is that it works for now and will only break when i'm about 20 more hours into this project and have completely forgotten about this code which is awesome anyway though putting a pin in that since we don't have a real file system to work with as you can see me writing in the background here our bootloader code kinda just looks at whatever's in the next sectors on the disk after the first one and says yeah sure whatever bro i'll run that without doing any checks or anything on it which is a highly highly secure way to write an operating system in a bootloader but after some fussing around with gcc again to get it to compile c code down to a flat binary instead of a regular executable we do basically exactly what we've done with the bootloader to get it onto our disk except we put the c code down onto the next sectors after the bootloader using as many as it takes since we don't care about anything else on this disk there are no files there's just nothing but tetris and we also need a lot more complicated boilerplate here to get c loading because yeah well remember when i mentioned earlier that this code is actually 16 bit yeah so actually all x86 processors boot in legacy mode for backwards compatibility reasons which is awesome until you want to write any software since like 1978 and want to use more than 64 kilobytes of memory technically neither of which we really need for tetris but i mean come on i'm not in the mood to be writing c targeting a 16-bit machine so we need to make the jump to 32-bit before we hop into c so anyway this requires a lot of complicated things like setting up a gdt and idt which well then where your bumpers are we'll be talking about them later also doing something called enabling the a20 line so that we can use all of our memory and a few other things here and there but after that we can finally let the cpu face its eyes on this fancy looking instruction here and take the jump to a high level language and by high level i mean c oh yeah and c without a standard library keep in mind so we're totally on our own for everything but still progress anyway the very first thing our wonderfully high level c code is going to do is another little hello world where it kind of just dangerously pokes into memory at this pre-configured address to write some data there which will magically get high to appear on the screen and now that that was working it was time for the first real honest to god game programming here writing our graphics driver so using the same interrupt hex 10 from earlier with the ah register set to zero this time we can actually request that the bias configure the video card in a bunch of different modes for our case we want clean crisp and colorful graphics so we'll be rolling with a huge 320 by 200 pixels on the screen with a whopping 8-bit fully configurable color palette and you can see the basic driver code going down in the background here you can see me struggling a lot messing around with some i o ports and things but soon enough we're able to upload our own palette to the graphics card which uses three bits each for red and green and two bits for blue for a total of eight bits or 256 possible colors and you can see the simple loops here i wrote to generate it i threw together another few lines of code two to put together the classic full screen palette tester and you can see that in action here but it is just kind of you know boring and lifeless there's no motion but how do we get like consistent motion here you know like a clock or a timer or something well if you're wondering like me boy do i have the crash course and x86 system internals for you so interrupts those things we use to load things from the disk and display stuff to the screen yeah now that we're in 32-bit land which we're in now those are all gone and we need to write our own code for configuring interrupts which means we need something called an idt or interrupt descriptor table and i won't go too deeply into detail here but this is basically just some big lists that will tell the processor what to do when it gets an interrupt or rather where to suspend and move execution to when an interrupt is triggered and who triggers interrupts well a lot of things including the keyboard any highly deadly errors like division by zero and the one we care about right now the programmable interval timer or pit for short this bad boy here cruises along at precisely 1.193192 megahertz and we can configure it to suspend execution from whatever is currently going on in the processor and run some code at regular intervals using interrupts in our case we're running it at 363 hertz so 363 times per second exactly it says hey stop what you're doing and pay attention to me and when we do that we just increment a counter somewhere that says that one more tick of our 363 per second have passed and doing a big old time warp in the background here because this took way longer to set up than you would even be able to see in the time lapse we can use the timer in an infinite loop and boom the demo is moving now that that's rolling the next thing up is to throw something meaningful up on the screen that isn't just some pretty colors so again for our third and final hello world of the day we need to be able to draw text to the screen now normally if i was writing a game i would load up or photoshop or whatever open up an image file make some characters export the image and load it up in the game to draw each character but remember no file system here so no images we have to hard code in our font directly into the binary lucky for us doing a quick little google will take us to stack overflow where someone has graciously already constructed an 8x8 monospace pixel font that we can use looking at that though you're probably thinking that doesn't look much like an image how the hell are you gonna take those numbers and make characters out of them well using some fancy bit fiddling techniques we can use a font defined by eight numbers for each glyph one byte for each row and then each of the eight bits in each byte represent a pixel it's a little easier to visualize actually so this illustration will clear things up i hope anyway though using that and again tossing the bits from the font directly onto some predefined address for our video memory we have our third and final hello world for the day and now it really is tetris time well actually sorry i i lied there one last back endy thing to do so you know how we've just been throwing pixels at some memory address to draw things to the screen well that's all well and good but once we really start getting things moving it's going to start causing some screen tearing issues why well imagine this scenario first our code starts drawing something to the screen then the video card operating completely independently from our code decides it's about time to display what's ever in the video buffer to the screen our image is only halfway drawn at this point and then we finish drawing our image after the video card is done displaying things and so on and so on until we're completely out of sync with the video card so how do we mitigate this well we use the agile technique called double buffering where basically instead of using one frame buffer for everything we draw at the screen we actually have two called the front and a back buffer the front buffer contains whatever we currently want on the screen while the back buffer contain whatever we're currently working on drawing when the game is done drawing we do what's called a swap in graphics terminology and switch the pointers to the front and back buffer so the display shows whatever we're finished drawing and we can get to work in the other buffer for the next frame this way we won't ever end up displaying an incomplete image on the screen this is actually a lot less complicated than it sounds so it's pretty quick to implement and once it's done we can draw our first block to the screen and keep in mind here again we aren't able to make any sprites in an image editor the block sprite here is actually hard coded in or rather generated at runtime here just a few simple loops we'll do the trick and generate all of the color blocks we need to get a good looking tetris clone going once we have our single block adding in the board is simple internally it's represented as a 20 by 10 array of eight possible values one for each possible block color and an empty value so if we just repeat the code that we used to render one block changing up the position for each block we have something starting to look like a real tetris board it's time to get this to actually play tetris to start out we need to get these seven different tetraminos in here which i'm sure you'll recognize i decided to represent these internally almost exactly the same as the font using a binary number for each of them where a 1 represents a block and a 0 represents no block with each rotation hard coded in as well you can see me in the background here figuring that out what isn't depicted here is me staring at my second monitor looking at all the tetraminos and trying my hardest to convert these numbers from binary to hexadecimal in my head but after that with a few mistakes and the hexadecimal worked out we have a falling tetramino and back to the code to work in some rotation except that doesn't look quite right i wonder what i did wrong here well after i took a good look at the tetris wiki it turns out it was conceptualizing the rotation entirely incorrectly and the tetraminos actually rotate around their center so fixing that up in the hard coating we have a falling rotating t-block totally ready to do some fancy t-spins but to get those sweet sweet t-spins we need to capture some user input which means we unfortunately need a keyboard driver which means more operating system stuff and after a quick trip back to the tetris wiki for some level timings from the original version of the game and some more refactoring you can see me doing in the background here we finally have some real tetris looking gameplay actually wait wait what the is that that doesn't look quite right okay so after a little more bug fixing though we do finally have something that really looks and plays like tetris but one thing is off here and i can't really tell what it is something just seems wrong oh yeah i'm missing the literal core gameplay mechanic whoops so back to the code and after some miserable attempts and miscalculated bounds on some m copies the not quite right results of which you can see here we have lines disappearing next up we can use some of the font drawing code we have from earlier to render the score the number of lines completed and which level the player is on we can also use some of our block drawing functions to render the next tetramino coming up like some of the newer fancy versions of tetris do and same deal for the rest of the ui here i added in a cool little animated main menu made out of some tiles and a good-looking lost screen for when you inevitably fail to handle the never-ending stream of blocks and i went on after that with some more refactoring some more cleanup but well here's where things started to get a little funky remember back like 10 minutes ago when i mentioned this line back in the bootloader yeah right here is around when it started to cause problems see because this line was hex 20 and not x10 only part of the whole binary for the game was actually being loaded into memory like the bootloader would just kind of stop halfway through loading and say yep you're good to go let's run this thing and because of the ordering of the sections of the code this means that the code would always load just fine but the data would sometimes be missing which means the bug was hard to track down to say the least so after i lost my mind for a few hours trying to figure out what could be wrong i finally found this one character change it to be correct and could keep going and well once that's solved we have tetris so where do we go from here well there is one key component that was still lacking music this thing definitely needs some music it just feels kind of wrong to play the game of tetris without hearing the theme in the background so music was next up so to get this going back in the feudal age when the first computers were being put together from rocks and fire some dudes at ibm probably thought that it would be really nice if each computer included an onboard speaker that could make some fancy beeping noises and play music if you really just abuse the hell out of it so obviously to get some music going i wrote a quick driver for the pc speaker gave it a test and well uh that was um a noise maybe i'll have to go back to the drawing board here and after spending some time reading up on wikipedia about the way sound works the way the pc speaker works listening to various tracks from 90s video games on it i decided this just wasn't going to cut it i needed to do something more intense more ambitious i needed to ride a driver for a real modern sound card and by real and modern i mean the soundblaster 16. this masterpiece of hardware designed from creative has state of the art text straight out of 1997 which should be able to drive our tetris music just fine so i dove straight in after wasting hours of my life learning about the pc speaker i thought i would triple that time spent and comb through more wiki pages 25 year old websites and some very old documentation to figure out how the hell to get this thing to work but once i had poured in a sufficient amount of my life force into this code to get the driver to work drum roll please okay so not quite the whole tetris theme but it's a start sounding better than the pc speaker did at least so now for some music since this driver doesn't have to play any actual sound files i wrote a little basic utility on top of it that gives us up to eight tracks for music each of which can play one note at a time from either a sine wave triangle wave or noise to give us a selection of instruments off the top of my head i programmed in the melody just fine but this just wasn't going to cut it it definitely lacks something on its own so i had to of course bust out the virtual piano here and figure out the harmony and bass and again this just wasn't gonna do it like i'm already enough piano player as it is trying to do it through a computer keyboard just accentuates that so for the first time in channel history it's time to bust the camera out of the computer so let me just okay maybe a few more it'll come loose uh one more hit should do it all right this is pretty weird not doing a face reveal or anything too crazy but this is a little strange especially considering i'm doing this voice over in post anyway i'm going to use this keyboard here to figure out the harmony and baseline for the theme and with about a half hour trying to remember everything from the piano lessons i took when i was a teenager here's what we got [Music] not bad huh really gives you that feeling like you're back in the golden days of the ussr watching some blocks fall while you chill out on your nuclear sub hundreds of meters under the surface of the atlantic and i'm not trapped on a sub or anything but i do love a good game of tetris so time to give this bad boy its full test run music and all [Music] [Music] and that's it for the video we have a fully bootable dependency free operating system that can only run tetris which was our goal i i guess the code as per usual will be available on github if you want to take a look at it check out the readme if you want to try and run it and i will be insanely impressed if someone can get this running on some real hardware i would have tried myself but sadly i only have my mac and while i don't think mr tim apple would be too pleased if i tried to boot some bootlegged tetris clone operating system on his pristine unibody designed hardware anyway though thank you very much for watching and see you next time [Music] you
Info
Channel: jdh
Views: 321,957
Rating: 4.9695644 out of 5
Keywords: c++, programming, coding, opengl, graphics, java, gamedev, gaming, code, operating system, OS, assembly, tetris
Id: FaILnmUYS_U
Channel Id: undefined
Length: 22min 36sec (1356 seconds)
Published: Sun Apr 18 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.