开源软件名称(OpenSource Name):Overv/MineAssemble开源软件地址(OpenSource Url):https://github.com/Overv/MineAssemble开源编程语言(OpenSource Language):Assembly 78.8%开源软件介绍(OpenSource Introduction):MineAssembleMineAssemble is a tiny bootable Minecraft clone written partly in x86 assembly. I made it first and foremost because a university assignment required me to implement a game in assembly for a computer systems course. Because I had never implemented anything more complex than a "Hello World" bootloader before, I decided I wanted to learn about writing my own kernel code at the same time. Note that the goal of this project was not to write highly efficient hand-optimized assembly code, but rather to have fun and write code that balances readability and speed. This is primarily accomplished by proper commenting and consistent code structuring. Starting in assembly right away would be a bit too insane, so I first wrote a reference implementation in C using the SDL library, which can be found in the reference directory. I started writing it with the idea that if it was longer than 150 statements excluding boilerplate, it wouldn't be worth doing it in assembly. Like all estimates in the world of programming, this limit turned out to be a gross underestimate, reaching about 134 lines before adding the texture or even the input code. After completing the reference code, I wrote the kernel boilerplate code (setting up VGA, interrupts, etc.) and changed the reference C code to work with this. Then I began slowly porting everything to handwritten assembly. Unfortunately this turned out to be a lot more work than I expected, so currently a large fraction of the codebase is still in C. Slowly porting everything to assembly is an ongoing process. The code also isn't fully compatible with all systems yet. It seems to cause floating point exceptions on some setups. How to playQEMUTo run the game with QEMU, simply run Virtual machineIf you want to use virtualization software like VirtualBox, you can produce an
.iso image with You can also burn this image to a CD or DVD, but that is rather wasteful. Use the USB stick method to try it on real hardware unless it really isn't an option for some reason. USB stickBooting from an USB stick is an excellent way to try it on real hardware, but does involve a little bit more work. Note that this process will remove all data currently on the USB stick. Also, make sure to get the drive name right or you might accidentally wipe your hard drive!
Now reboot your PC and boot from USB. Debugging with GDB and QEMU
Building a cross compiler toolchainIn order to build MineAssemble, you need to have a cross compiler toolchain consisting of the GNU Binutils and GNU C Compiler (GCC). The toolchain must be built for i686-pc-elf target. For legacy reasons, GNU GCC and Binutils are configured at compile time and you will need to compile them from source to create a cross compiler toolchain. You will also need the NASM Assembler. In addition, you might need QEMU for testing MineAssemble in an emulator and the GNU Debugger (GDB) for debugging. Installing prerequisitesYou will need to install a handful of utility libraries to build Binutils, GCC, QEMU and GDB. Use your operating system's equivalent for apt-get or compile from source. libmpc, libgmp, libmpfr (required for binutils, gcc and gdb)Install
flex and bison (required for GCC)Install
libsdl (optional front end for qemu)Install
NASMInstallNASM does not need to be configured at compile time, you can install it using your package manager.
Create directories for source, build files and binaries
Get source code for Binutils, GCC, QEMU and GDB
Check out latest release versions
Build binutils for target i686-pc-elf
Build GCC (C compiler only) for target i686-pc-elf
Build qemu with i386-softmmu target (with SDL front end)
Build GDB for i686-pc-elf target
Add toolchain to $PATH
Style conventionsWith something as low-level as assembly, you quickly risk writing unreadable code if you don't have proper style conventions. This project uses the following identifier name conventions:
Variable names carry no type prefix, because it is almost always very clear what type a variable uses from its name or usage. Here are some examples:
Directives that apply to segments of a file or the whole file, such as
have no indentation. Subroutines and local labels have one level of indentation and code or data within have two levels of indentation. One level of indentation is equal to 4 spaces. Code is commonly separated in blocks with a comment above describing what is done in the block. If a line requires extra explanation, a comment is placed after the instruction. Floating point math expressions are systematically converted from the reference infix expression to RPN (Reverse Polish Notation) to FPU instructions. Any optimizations are applied afterwards if deemed necessary. This systematic approach makes converting single-line C expressions to dozens of assembly instructions bearable and relatively error-free. ExplanationThe inner workings of this demo are really quite straight-forward. The code can be divided into four different components. WorldThe world is stored as an unsigned byte array where every block has a value of
either While playing, other code calls Input and collisionKeyboard input is collected by an IRQ1 interrupt handler. It writes the up/down
state to a 128-byte array indexed by the scan code.
It also sets the upper bit to Because the input handling needs to be independent of performance, an IRQ0
interrupt handler increases a Before every frame is rendered, the After that, the update function is called to move the player according to the
current velocity. This velocity is controlled partly by the Before the new position is assigned, the code first runs the RenderingNormally games use rasterization to render and this is very fast. Unfortunately a graphics library like OpenGL is not available at this level. Instead, code needs to be written that writes directly to the graphics memory. At this point, I had two choices: write my own rasterizer or implement a raytracer. I decided to go with raytracing, because:
The raytrace algorithm computes the distance to reach the sides of the block
the ray starts in for every dimension. The shortest distance wins and the ray
position is moved by that distance times the ray direction. This is repeated
until the position is inside a ResourcesOne of the details you deal with when using a low-level VGA mode (mode So I decided to generate a palette that could represent every color that the textures used exactly, well almost exactly. The palette does allow you to specify RGB colors, but with only 6 bits per channel instead of 8. That means that colors will be slightly off, but this is pretty much unnoticeable. I wrote a program in C# that took the grass, dirt and side textures along with the reserved colors black, white and sky and automatically generated a palette and a palette colored representation of the three textures. This ended up working perfectly! The splash screen works slightly differently. The reason that it's a bitmap instead of just using text mode is to make things a bit more streamlined. I first tried encoding it the same way as the textures, but this resulted in a 6400 line C file. Then I changed it to simply write a string of 1's and 0's for every line, which works much better. It even allows you to view the splash screen using a text editor! :-) The bitmap of the splash screen is copied directly to VGA memory where LicenseThis project is licensed under the MIT license. Some derived work with compatible licensing is also included:
Derived work here means that the code was adapted to fit the requirements of this project. |
2023-10-27
2022-08-15
2022-08-17
2022-09-23
2022-08-13
请发表评论