stardance has been extended another month! the new deadline is october 31 :)

You are browsing as a guest. Sign up (or log in) to start making projects!

Suckless chip-8 emu

  • 5 Devlogs
  • 12 Total hours

(mostly) Suckless Chip-8 emulator built in C using ncurses as its graphics engine

Ship #1 Pending review

A suckless complete CHIP-8 emulator written in C!

What is in it?

  • All instructions the original CHIP-8 architecture supported
  • Graphical output to the terminal using (my beloved) ncurses
  • Loading .ch8 roms
  • Error handling with stderr

What am I proud of?

I am really proud of the optimizations i did for the project after pretty much finishing it. I am also proud of the way i implemented the keyboard (which was really hard) and the way it turned out. I am also proud of the error handling because it helped me level up in my overall knowledge in knowing how to handle errors.

How is it built?

It’s built in C using ncurses, following the suckless philosophy (optimized and only one source file) and most of the suckless style guide. There is a precompiled binary that was built with GitHub workflows using Ubuntu. The binary can be directly downloaded from the repo’s release page and can be used on (most) glibc-based Linux distros (build is compiled for Ubuntu and ncurses-v6 has to be installed on your system, original project was made with NixOS, which will also work).

What I learned

I learned how CPU’s operate (fetch, decode, execute), i learned about opcodes and parsing and i learned using bitwise operators effectively. It also taught me the importance of hexadecimal in programming. The project overall brought me closer to CompEng and how CPU’s work on a rudimentary level. It also taught me (as said) how to handle errors better and i think because of trying to make the project as suckless as possible the project also made me an overall better programmer.

Known limitations / plans for the future

Bugs can occur, even though no error that isn’t being handled by the program itself has been recorded. Still look out for bugs and if any are found write it to me as feedback please.

As this project is a full emulator for CHIP-8 there isn’t that much to be done anymore which i am really proud of :)

Closing word

This project was pretty fun to make and it taught me a bunch. It is also my final project for Stardance which is a bit sad but i don’t/didn’t have enough time to start a new project which is why i will stop with this. Still i loved Stardance and it brought me closer to CE/SE than i would ever think i would get (before hearing of Stardance i wasn’t really fond of coding). To anyone reading this whole thing: Love y’all :)))

  • 5 devlogs
  • 12h
Try project → See source code →
Open comments for this post

2h 21m 27s logged

LOG 5: LAST LOG BEFORE SHIP, MADE THE PROJECT MOSTLY SUCKLESS,

REWORKED KEYBOARD, ADDED A DIE FUNCTION, ROMS ARE NOW LOADED VIA
TERMINAL, ADDED MACROS, ADDED README

FEATURES

“SUCKLESS”

I made the program (i think) as much compliant to the suckless philosophy as i can and did most of (not all of) the stylistic choices mentioned in the suckless style guide. I think making it suckless majorly improved the program

KEYBOARD REWORK

Because i decided i wanted to make the project basically suckless i have decided that i needed to rework the keyboard functions. I replaced the keyboard struct with long long keyboard[16]. The index is now the key and the value is the value that key_pressed compares against when the instrcutions are called. key_pressed returns (now - keypad[k]) < ACCEPTABLE_DISTANCE which made the logic way smaller and easier to read. I also replaced the ~ 60 lines key switch statement with a single array that has all the characters of the Chip-8 keyboard and compares it using strchr with the input ch and the difference between the return value of strchr and the positon of keyboard[0] is the index which the current time is written into

DIE FUNCTION

I added a die function that replaces all early exit functions that would kill the entire program. It gets an input string and other parameters (like printf would get) and print it to stderr. It does this by using varargs. If initscr() has been called it also does endwin() and if not it doesnt (a bool is turned to true after initscr() has been called). Because of this read_rom is now void because every error path calls die instead of returning false. fopen also calls strerror if it fails to display WHY fopen has failed

TERMINAL INPUT

Previously rom names were hardcoded into the program and had to be changed and recompiled if i wanted to change them. Now the program takes in multiple arguments (2 in total, more or less results in an error after which the proper usage is displayed) and the rom (if found) is copied and executed which makes testing multiple programs way easier.

MACROS

I removed magic number and replaced them with macros to make the code more readable and theoretically modifiable.

README

I added a README in the repo that explains pretty much everything that you would need to know before using the program

0
0
16
Open comments for this post

2h 2m 51s logged

LOG 4: KEYBOARD IS FINALLY FUNCTIONAL FOR (hopefully) ALL INSTRUCTIONS!!!! (and some bug fixes)

After a long battle with the code i finally figured out how to implement the keyboard without the keys only being picked up every once in a while.

HOW DID I DO IT?

Previously the keyboard was simple a bool array and if i a button was pressed the corresponding part of the keypad array was turned true. The issue with that was that with this simple implementation there had to be one of 2 mandatory pay-offs: Case A would be that the keys would be sticky and never get turned false, Case B would be that they get reset on every iteration of the main loop which is too fast for instructions 0x9E and 0xA1 in certain programs, as they need the value for multiple iterations. Simply holding down the key was actually too slow because of the way holding down a key works on linux which is why i had to do the following implmentation:

Step A:

  • Get the current pressed button, turn it to true and save the time the button was pressed

Step B:

  • Get the time distance between when the button was pressed and the current time .
  • Loop through the keyboard array and check for keys that are true
  • If a key is true and if the time distance is larger/equal than/to the threshold (50 ms), turn that key false.
  • Following from this if the distance is smaller or equal to the acceptable distance the key stays true and the loop can work with it.

BUG FIXES

ISSUE WITH INSTRUCTION 0x8xy6 and 0x8xyE

Previously 0x8xy6 and 0x8xyE bitshifted chip.v_reg[x] either « 1 or » 1 which i found out was false after rereading the docs because a test code wasnt working properly. The fix was just to implement the correct instruction (chip.v_reg[x] = chip.v_reg[y] « 1 or the same using » 1)

0
0
12
Open comments for this post

3h 31m 25s logged

LOG 3: ROM LOADER, GRAPHICS ENGINE, KEYBOARD, FONTSET, TEST CODE

FOREWORD

FEATURES

I kinda didnt click post on my last devlog which is why this is a combination of two devlogs but ig this has to suffice

ROM LOADER

I implemented a rom loader that opens and copies roms (.ch8 files) and then executes their instructions when the program runs. The rom reader opens the file with fopen and reads them into memory using fread once.

GRAPHICS ENGINE

I use my (beloved) ncurses for graphics and a function is called every cycle to print out the graphics on the 64x32 screen using either # for spots where the graphic display is true and ’ ’ for spots where it isnt

KEYBOARD

The keyboard uses getch that doesnt stop the loop but rather just listens for input and then sets the keyboard value of the pressed button to true

FONTSET

The fontset is pretty basic (its just an array of the standard chip-8 fontset that gets loaded into the memory array starting from 0x50)

TEST CODE

Ive written some very basic test code for testing purposes. Current functions are printing to the screen, setting variables and printing when a button is pressed. I coded the code in hex and used hexed.it to convert the hex code into .ch8 files

BUG FIXES

Luckily there where no major bugs previously in the code (there wasnt that much to be buggy) but obviously there where issues on the way to the current code. Because i dont remember everything i fixed on the way i wont list it in todays devlog (overall i just list bugs if they where in a previious commited/devlogged version)

0
0
19
Open comments for this post

3h 0m 51s logged

LOG 2: KNOWING WHAT TO DO, IMPLEMENTED ALL INSTRUCTIONS

WHAT KIND OF CPU AM I BUILDING?

I am building a CHIP-8 CPU emulator in C based on the specifications at http://devernay.free.fr/hacks/chip8/C8TECH10.HTM.

CURRENT FEATURES

Currently i have implemented all of the regular CHIP-8 instructions that are listed on the source website. They are detected by checking for the specific flags and then execute code based on their variables. There are a total amount of 33 instructions available (normally there are 34 for CHIP-8 but one isn’t used in emulators). Currently the CPU cannot take instructions (will be implemented next probably)

0
0
27
Open comments for this post

1h 11m 2s logged

LOG 1: MY OWN CPU EMULATOR

IDEA

I want to build my own CPU emulator for either a self built or Chip-8 architecture. Im very unsure which direction i want to go right now but i find the idea really interesting which is why i just started doing it. The project will (probably) be written fully in C and i hope that it will be able to run real programs. I hope the project will give me a better insight into how cpus and computers work in general

CURRENT FEATURES

Currently the CPU can add values to and jump between register and finally terminate itself. The values that are added/subtracted are set before compilation.

0
0
33

Delete project?

Are you sure you want to permanently delete this project? This action cannot be undone.

All devlogs, followers, and associated data will be removed.

Followers

Loading…