Update mailing list
[chip8.git] / README.md
blobd506ab1c6111b90d490c437c7d27e15467391ce9
1 ![CHIP-8 logo](https://i.imgur.com/fHXLgX0.png "CHIP-8 logo")
3 # c8emul
4 CHIP-8 emulator implemented in C99 using the SDL2 multimedia library. It implements all the opcodes of a standard
5 CHIP-8 but without sound.
7 ## Features
8 * Quality
9     * Compiled with security hardening flags.
10     * Static analysis integrated using clang's `scan-build` using checkers `alpha.security`, `alpha.core.CastSize`,
11     `alpha.core.CastToStruct`, `alpha.core.IdenticalExpr`, `alpha.core.PointerArithm`, `alpha.core.PointerSub`,
12     `alpha.core.SizeofPtr`, `alpha.core.TestAfterDivZero`, `alpha.unix`.
13     * Follows [FreeBSD coding style](https://www.freebsd.org/cgi/man.cgi?query=style&sektion=9).
14     * Test harness: opcodes are unit tested.
15 * Portable
16     * C99 compliant.
17     * Uses [SDL2](https://www.libsdl.org) as the only dependency.
18     * Easy to compile and uses POSIX make.
20 ## Limitations
21 * Audio is not supported
23 ## Build dependencies
24 Other than [SDL2](https://www.libsdl.org), the only other dependency is a toolchain supporting the following flags:
26 ```
27 CFLAGS = -std=c99 -O2 -Wall -Wextra -Wpedantic \
28         -Walloca -Wcast-qual -Wconversion -Wformat=2 -Wformat-security \
29         -Wnull-dereference -Wstack-protector -Wvla -Warray-bounds \
30         -Wbad-function-cast -Wconversion -Wshadow -Wstrict-overflow=4 -Wundef \
31         -Wstrict-prototypes -Wswitch-default -Wfloat-equal \
32         -Wpointer-arith -Wswitch-enum \
33         -D_FORTIFY_SOURCE=2 \
34         `sdl2-config --cflags` \
35         -fstack-protector-strong -fPIE -fstack-clash-protection
37 LDFLAGS = -Wl,-z,relro -Wl,-z,now -Wl,-z,noexecstack -Wl,-z,separate-code
38 ```
40 Otherwise you can just remove the security flags and compile it with
41 ```
42 CFLAGS = -std=c99 -O2 -Wall -Wextra -Wpedantic `sdl2-config --cflags`
43 LDFLAGS =
44 ```
46 or pass your own flags to make
47 ```sh
48 make CC=gcc CFLAGS=... LDFLAGS=...
49 ```
51 ## Installation
52 Clone this repository then
54 ```sh
55 $ make PREFIX=/usr install
56 ```
58 This will install the compiled binary under `PREFIX` (`/usr/bin`) in this case, if not specified `PREFIX` will default
59 to `/usr/local`. For staged installs, `DESTDIR` is also supported.
61 ## Usage
62 **c8emul** receives as input a ROM file and executes it displaying the output in a window of default size 64x32 and
63 with a delay between each cycle of 3ms. The ROM file however, can be omitted, in this case the program takes the input
64 from the standard input until `EOF` or `^D` is reached.
66 The options are as follows:
68 * **-s** Specify the `scaling_factor`, i.e. a multiplier that controls how to scale the default 64x32 window size.
69 * **-d** Specify the delay in milliseconds between cycles.
71 ### Examples
72 Load ROM from stdin and display it in 640x320 with the default 3ms cycle delay:
73 ```sh
74 $ c8emul -s 10
75 ```
76 Load ROM from file and scale the window to 640x320 with a 2ms cycle delay:
77 ```sh
78 $ c8emul -s 10 -d 2 Chip8_Picture.ch8
79 ```
81 ### Test suite
82 The test suite consists of a series of unit tests, one for each opcode (excluding Cxkk and Dxyn) and for the
83 intialization of the emulator. The suite is contained in the `test` folder. It's output is similar to
84 [googletest](https://github.com/google/googletest)'s and it can be invoked with `make check` which, if
85 everything is working should output something similar to
86 ```
87 ./tests
88 [----------] Test environment set-up.
89 [==========] Running test cases.
90 [ RUN      ] PC set to 0x200
91 [       OK ] PC set to 0x200
92 [ RUN      ] Font is loaded
93 [       OK ] Font is loaded
94 [ RUN      ] 00E0: display cleared
95 [       OK ] 00E0: display cleared
96 [ RUN      ] 00EE: RET from subroutine
97 [       OK ] 00EE: RET from subroutine
98 [ RUN      ] 1123: JMP to location 0x123
99 [       OK ] 1123: JMP to location 0x123
100 [ RUN      ] 2456: call subroutine at addr 0x456
101 [       OK ] 2456: call subroutine at addr 0x456
102 [ RUN      ] 3879: skip next instruction, V8 = 0x79
103 [       OK ] 3879: skip next instruction, V8 = 0x79
104 [ RUN      ] 4123: skip next instruction, V1 != 0x23
105 [       OK ] 4123: skip next instruction, V1 != 0x23
106 [ RUN      ] 5210: skip next instruction, V2 = V1
107 [       OK ] 5210: skip next instruction, V2 = V1
108 [ RUN      ] 6456: set V4 = 0x56
109 [       OK ] 6456: set V4 = 0x56
110 [ RUN      ] 7789: set V7 = 0x89
111 [       OK ] 7789: set V7 = 0x89
112 [ RUN      ] 8980: set V9 = V8
113 [       OK ] 8980: set V9 = V8
114 [ RUN      ] 8981: set V9 = V9 OR V8
115 [       OK ] 8981: set V9 = V9 OR V8
116 [ RUN      ] 8982: set V9 = V9 AND V8
117 [       OK ] 8982: set V9 = V9 AND V8
118 [ RUN      ] 8983: set V9 = V9 XOR V8
119 [       OK ] 8983: set V9 = V9 XOR V8
120 [ RUN      ] 8984: set V9 = V9 + V8, VF = carry
121 [       OK ] 8984: set V9 = V9 + V8, VF = carry
122 [ RUN      ] 8985: set V9 = V9 - V8, VF = not borrow
123 [       OK ] 8985: set V9 = V9 - V8, VF = not borrow
124 [ RUN      ] 8986: set V9 = V9 SHR 1
125 [       OK ] 8986: set V9 = V9 SHR 1
126 [ RUN      ] 8987: set V9 = V8 - V9, VF = not borrow
127 [       OK ] 8987: set V9 = V8 - V9, VF = not borrow
128 [ RUN      ] 898E: set V9 = V9 SHL 1
129 [       OK ] 898E: set V9 = V9 SHL 1
130 [ RUN      ] 9120: skip next instruction, V1 != V2
131 [       OK ] 9120: skip next instruction, V1 != V2
132 [ RUN      ] A123: set I to 0x123
133 [       OK ] A123: set I to 0x123
134 [ RUN      ] B345: jump to location 0x345 + 0x12 (V0)
135 [       OK ] B345: jump to location 0x345 + 0x12 (V0)
136 [ RUN      ] E69E: skip next instruction, key with value of V6 is pressed
137 [       OK ] E69E: skip next instruction, key with value of V6 is pressed
138 [ RUN      ] E1A1: skip next instruction, key with value of V1 is not pressed
139 [       OK ] E1A1: skip next instruction, key with value of V1 is not pressed
140 [ RUN      ] F507: set V5 to delay timer value
141 [       OK ] F507: set V5 to delay timer value
142 [ RUN      ] F20A: key 'x' is pressed, V2 = 0
143 [       OK ] F20A: key 'x' is pressed, V2 = 0
144 [ RUN      ] F515: set delay timer = V5
145 [       OK ] F515: set delay timer = V5
146 [ RUN      ] F718: set sound timer = V7
147 [       OK ] F718: set sound timer = V7
148 [ RUN      ] F01E: set I = I + V0
149 [       OK ] F01E: set I = I + V0
150 [ RUN      ] F929: set I to location of sprite of '2'
151 [       OK ] F929: set I to location of sprite of '2'
152 [ RUN      ] F333: store BCD representation of V3 in memory locations I, I+1, I+2
153 [       OK ] F333: store BCD representation of V3 in memory locations I, I+1, I+2
154 [ RUN      ] F255: store registers V0-V2 in memory starting from location I
155 [       OK ] F255: store registers V0-V2 in memory starting from location I
156 [ RUN      ] F165: read registers V0-V1 in memory starting from location I
157 [       OK ] F165: read registers V0-V1 in memory starting from location I
158 [==========] 34 test cases ran.
159 [  PASSED  ] 34 tests.
160 [  FAILED  ] 0 tests.
161 [----------] Test environment teardown.
164 ### Static analysis
165 Static analysis on the code base is done by using clang's static analyzer run through `scan-build.sh` which wraps the
166 `scan-build` utility. The checkers used are part of the
167 [Experimental Checkers](https://releases.llvm.org/12.0.0/tools/clang/docs/analyzer/checkers.html#alpha-checkers)
168 (aka *alpha* checkers):
170 * `alpha.security`
171 * `alpha.core.CastSize`
172 * `alpha.core.CastToStruct`
173 * `alpha.core.IdenticalExpr`
174 * `alpha.core.PointerArithm`
175 * `alpha.core.PointerSub`
176 * `alpha.core.SizeofPtr`
177 * `alpha.core.TestAfterDivZero`
178 * `alpha.unix`
180 ## Contributing
181 Send patches on the [mailing list](https://www.freelists.org/list/chip8-dev), report bugs on the [issue tracker](https://todo.sr.ht/~spidernet/chip8). 
183 ## License
184 BSD 2-Clause FreeBSD License, see LICENSE.