diff --git a/500.html b/500.html new file mode 100644 index 0000000..16605c8 --- /dev/null +++ b/500.html @@ -0,0 +1,71 @@ + + + Matthilde's Home + + + + + +

Matthilde's Home Page

+

Oopsie Doopsie >~<

+
+

[ Ouchie ]

+ +
+

502 Bad Gateway

+

Looks like my website is offline. If you see this, that probably means I am experiencing issues with my webserver. My tilde however, is probably still available.

+
+ +
+ -- EOF -- + + diff --git a/src/b.md b/src/b.md index 0f0a89b..7581bd0 100644 --- a/src/b.md +++ b/src/b.md @@ -2,5 +2,6 @@ Here is my awesome blog where I will post awesome posts. Anyways, pick a post +[-=- New Project: the VICERA Fantasy Computer (Part I) -=-](b/vicera_part1.html) [-=- Switching from CloudFlare to a VPS -=-](/b/bye_cloudflare.html) [-=- Roguelike in 350 lines of C -=-](/b/c_roguelike.html) diff --git a/src/b/vicera_part1.md b/src/b/vicera_part1.md new file mode 100644 index 0000000..02a1231 --- /dev/null +++ b/src/b/vicera_part1.md @@ -0,0 +1,241 @@ +# The VICERA: Part I + +## Introduction + +This project is probably the biggest I have ever done so far in my life. Which +is not even finished yet. I have already worked on it for now a month and I +think it deserves it's very own series of blog. + +VICERA is a 8-bit fantasy console heavily inspired by many aspects of the +Gameboy architecture (mostly in the CPU). All the core components are written +in standard C. Only `main.c` and the SDL front-end aren't. That means it is +pretty much portable and writing your own front-end should not be a difficult +task. + +To people who doesn't know what fantasy consoles are: They are most likely game +engines running on a virtual machine specifically designed for it simulating +the harsh hardware limitations of retro consoles or computers. + +So far, the console, still in development, has arrived at a point of stability +and it can now be used. At the time of writing, no games has been created on it +yet. You can build it yourself from source by cloning [this repository](https://github.com/vicera/vicera). + +This blog will be divided into multiple parts. + +**NOTE**: This blog is really long. + +## 0. The console + +So the projects starts here. Nothing, just my whiteboard to start designing the +whole project. I first started designing the whole thing in a "quick" way to +get an approximative idea of how the project is going to look like. + +So I started thinking, and I thought about a simple console, easy to implement +which would be also easily portable with pretty harsh hardware limitations. + +At this point I started looking up this [Gameboy Programming Manual](http://marc.rawer.de/Gameboy/Docs/GBCPUman.pdf) +and this is where I started having a more precise idea of the CPU. + +## 1. The CPU + +So that said, the CPU will be close to the Gameboy architecture, but with less +instructions, registers and flags so it is easy to implement (plus 2 +instructions taken from the Intel x86 architecture). + +To know about the CPU architecture, you can look up the [VICERA documentation](/vicera/p/cpu.html). +It documents everything about the CPU. + +The implementation wasn't a difficult task but more of a boring, repetitive +task most of the time. I had to write a function for every instructions and then +write a huge switch-case block. + +The CPU has 7 registers, a stack pointer, a program counter, 2 flags and needs +64 KiB of memory. So I have made a `struct` to carry all this information +through all the functions: + + struct CPU { + // 64kb Memory bank. + BYTE memory[0x10000]; + // Registers + BYTE registers[REGSIZE]; + // Program Counter + WORD pc; + // Stack pointer + WORD sp; + // Flags + BYTE flags; + // Is it running? + BYTE running; + } + +Oh I forgot to mention that I have defined `BYTE` and `WORD` to shorten the +definition of specific integers, + + // Types definitions + typedef unsigned char BYTE; + typedef unsigned short int WORD; + +Every instruction has it's own function. We will use the `xor` instruction as an +example for my blog: + + // xor r + // XOR instruction with a register as an argument. + void xor_r(struct CPU* cpu, int reg_a) + { + // Takes the register from an intermediate function named get_register + BYTE *r = get_register(cpu, reg_a); + + // Performs a XOR operation with the taken value + cpu->registers[REG_A] ^= *r; + } + + // xor n + // Same thing but with a direct value. + void xor_n(struct CPU* cpu, BYTE byte_a) + { + cpu->registers[REG_A] ^= byte_a; + } + +As mentionned in this block of code, I have used a few intermediate functions +to avoid repetition and makes development easier. Here two of those: + + // BYTE, BYTE -> WORD + // converts two bytes into a word. + WORD btoword(BYTE byte_a, BYTE byte_b) + { + return (byte_a * 0x100) + byte_b; + } + + // struct *CPU -> WORD + // returns a 16-bit value from the two following bytes + // in the RAM starting from (PC + 1) + WORD memword(struct CPU *cpu) + { + return btoword(cpu->memory[cpu->pc + 1], + cpu->memory[cpu->pc + 2]); + } + +I have also made two debugging functions to dump memory or registers. +Both named respectively `dump_memory` and `dump_registers`. + +There comes the really long O' big switch-case block. I have setted up a big +`enum` with all the instructions then bound every opcode into their matching +function. + +Now I have finished implementing the CPU, what now? How can I program it? +To answer this question, I have wrote a little toy assembler (which can be +found in the GitHub repo, refer to the _External Links_ at the bottom of the +blog.) which has the very basic features of a typical assembler, such as +assembling bytecode (of course), labels and that's it. Yea this is it, just +bytecode and labels. But it was enough to play arround with the CPU and write +some basic programs. But having just a CPU is boring, we need more... + +## The GPU + +Of course, what would be a video game console without a display? The GPU was +pretty easy to implement. It took me only an hour or two to implement just the +GPU and half an hour to implement the SDL front-end. + +The GPU will have a 256x256 which only 160x160 of the canvas can be displayed +by the console screen. It has 3 registers in the memory. One that increments +on screen refresh, and two to scroll arround the screen, letting the programmer +point where to display. + +Like the CPU, the GPU has it's own struct so I can carry arround all the needed +data when calling functions, + + // GPU struct + struct GPU + { + // The screen itself. + char screen[SCREEN_X][SCREEN_Y]; + // Scrolling + struct GPU_Point scroll; + // Pointer to CPU struct + struct CPU *cpu; + } + +The GPU works with tiles and sprites, that means that there is no direct +modification of the screen buffer from the CPU. The GPU don't even have any +direct communication with the CPU, it is independent. The usage of the CPU +struct is only to access the memory. + +So the rest of implementation is inserting in the buffer the tiles and sprites +specified in the memory between 0x8000 and 0x9000 (VRAM, again, for all that +technical information, you can refer to the documentation in the _External Links_) + +The SDL impl. was also really simple: + + - Spawn a renderer and a window. + - Make a loop. + - Call `render_screen` from the GPU. + - Place pixels from the buffer from `SCROLLX`x`SCROLLY` to `(SCROLLX + 160) % 256`x`(SCROLLY + 160) % 256` + - Update screen + - Continue the loop until the CPU halts or the user exits the app. + +## The SPU + +There is not much information about it since I haven't really worked on it yet. +The actual design is that there are 3 channels, one for melody, one for bass, and +one for noise (cool for SFXs). + +There is a small impl. that you can look up on the GitHub repo (`spu.c` and +`spu.h`) but no SDL front-end for now. + +## Configuration + +The configuration was not an easy task since I have never really parsed strings +in C. So I decided to make a configuration system that is convenient to use and +easy to implement. I thought about the INI files, so I did a simplified version +of INI. (basically INI without sections) + +The implementation was easy like I expected it to be, just a few `strtok` calls +and an handler. You write a function that consumes two strings as arguments and +the parser will call this function everytime it parses a value. I got inspired +from [this simple INI Parser](https://github.com/benhoyt/inih). + +Here is the default configuration for the VICERA: + + # This is the default configuration + # Directional arrows -> Keyboard arrows + # A, B -> Z, X + # Start, Select -> Enter, Backspace + + # Directional arrows + controller.left = 1073741903 + controller.down = 1073741905 + controller.right = 1073741904 + controller.up = 1073741906 + + # Buttons + controller.a = 122 + controller.b = 120 + controller.start = 13 + controller.select = 8 + +## Conclusion + +I have learned a lot from this project that is not even finished. I have +learned more about how a CPU works, how these old handheld Nintendo classics +worked (I did lots of research while working on this project) and how to plan +and maintain a project properly. + +I also got more confident writing programs in C by writing this fantasy console. + +Right now I am improving the programming experience by optimizing a few things +in the CPU and by writing an assembler. + +Once done, I will try and port a C compiler for the CPU. + +See you later for the Part 2 if ever I write it! + +## External Links + +Here is a few links and websites I have visited while programming the VICERA. + +[The Gameboy CPU Manual](http://marc.rawer.de/Gameboy/Docs/GBCPUman.pdf) +[(almost) Z80 Assembly programming for the Gameboy and Gameboy Color](https://www.chibiakumas.com/z80/Gameboy.php) +[VICERA official GitHub repository](https://github.com/vicera/vicera) +[VICERA official documentation](https://h3liu.ml/vicera/) +[SDL 2.0 Wiki](https://wiki.libsdl.org) +[INIH: A simple C INI parser](https://github.com/benhoyt/inih) diff --git a/src/index.md b/src/index.md index 3b49f71..61644aa 100644 --- a/src/index.md +++ b/src/index.md @@ -5,3 +5,5 @@ This is where you can get to know me and look at what I make. I will also post b Also look at [my shitpost website](http://matthilde.is-dummy-thi.cc). You should also check out [my best friend's site.](//solarr.h3liu.ml) (she makes art). + +