Explicitly write out inference rule for .c.o
[chip8.git] / test / tests.c
bloba1ecb22ad20cb3aa93c9968f3028b15f3825cadc
1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
4 * Copyright (c) 2021 Alessio Chiapperini.
5 * All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <time.h>
34 #include "../src/chip8.h"
36 static int count_pass;
37 static int count_fail;
38 static uint8_t fontset[FONTSIZ] = {
39 0xF0, 0x90, 0x90, 0x90, 0xF0, /* 0 */
40 0x20, 0x60, 0x20, 0x20, 0x70, /* 1 */
41 0xF0, 0x10, 0xF0, 0x80, 0xF0, /* 2 */
42 0xF0, 0x10, 0xF0, 0x10, 0xF0, /* 3 */
43 0x90, 0x90, 0xF0, 0x10, 0x10, /* 4 */
44 0xF0, 0x80, 0xF0, 0x10, 0xF0, /* 5 */
45 0xF0, 0x80, 0xF0, 0x90, 0xF0, /* 6 */
46 0xF0, 0x10, 0x20, 0x40, 0x40, /* 7 */
47 0xF0, 0x90, 0xF0, 0x90, 0xF0, /* 8 */
48 0xF0, 0x90, 0xF0, 0x10, 0xF0, /* 9 */
49 0xF0, 0x90, 0xF0, 0x90, 0x90, /* A */
50 0xE0, 0x90, 0xE0, 0x90, 0xE0, /* B */
51 0xF0, 0x80, 0x80, 0x80, 0xF0, /* C */
52 0xE0, 0x90, 0x90, 0x90, 0xE0, /* D */
53 0xF0, 0x80, 0xF0, 0x80, 0xF0, /* E */
54 0xF0, 0x80, 0xF0, 0x80, 0x80 /* F */
57 #define TEST(exp, test_name) \
58 do { \
59 (void)printf("[ %-8s ] " test_name "\n", "RUN"); \
60 if (exp) { \
61 (void)printf("[ %8s ] " test_name "\n", "OK"); \
62 count_pass++; \
63 } else { \
64 (void)printf("[ %8s ] " test_name "\n", "NOK"); \
65 count_fail++; \
66 } \
67 } while (0)
69 static void
70 setup(struct chip8 *c)
72 chip8_init(c);
73 srand((unsigned int) time(0));
74 printf("[----------] Test environment set-up.\n");
77 static void
78 teardown(void)
80 printf("[----------] Test environment teardown.\n");
83 static void
84 putopcode(uint16_t opcode, struct chip8 *c, size_t pos)
86 c->memory[pos] = opcode >> 8;
87 c->memory[pos + 1] = opcode & 0xFF;
90 int
91 main(void)
93 struct chip8 c;
94 int test;
96 setup(&c);
97 (void)printf("[==========] Running test cases.\n");
99 test = 0;
100 /* PC must be set to 0x200 */
102 test++;
103 TEST(c.pc == 0x200, "PC set to 0x200");
106 /* Font is loaded into memory */
108 int isloaded = 1;
109 test++;
111 for (size_t i = 0; i < FONTSIZ && isloaded != 0; i++) {
112 if (c.memory[FONT_STARTADDR + i] != fontset[i]) {
113 isloaded = 0;
116 TEST(isloaded == 1, "Font is loaded");
119 /* 00E0: display should be cleared */
121 int isclear = 1;
122 test++;
124 putopcode(0x00E0, &c, c.pc);
125 chip8_step(&c);
126 for (size_t px = 0; px < WIDTH * HEIGHT && isclear != 0; px++) {
127 if (c.display[px] != 0) {
128 isclear = 0;
131 TEST(isclear == 1, "00E0: display cleared");
134 /* 00EE: return from subroutine */
136 uint8_t osp = ++c.sp;
137 test++;
139 putopcode(0x00EE, &c, c.pc);
140 chip8_step(&c);
141 TEST((--osp == c.sp) && (c.pc == c.stack[c.sp]),
142 "00EE: RET from subroutine");
145 /* 1123: jmp to location 0x123, pc = 0x123 */
147 test++;
149 putopcode(0x1123, &c, c.pc);
150 chip8_step(&c);
151 TEST(c.pc == 0x123, "1123: JMP to location 0x123");
154 /* 2456: call subroutine at addr 0x456 */
156 test++;
157 c.pc = 0x55;
158 c.sp = 0;
160 putopcode(0x2456, &c, c.pc);
161 chip8_step(&c);
162 TEST((c.stack[0] == 0x57) && (c.sp == 1) &&
163 (c.pc == 0x456), "2456: call subroutine at addr 0x456");
166 /* 3879: skip next instruction if V8 = 0x79 */
168 test++;
169 c.registers[8] = 0x79;
170 c.pc = 0;
172 putopcode(0x3879, &c, c.pc);
173 chip8_step(&c);
174 TEST(c.pc == 4, "3879: skip next instruction, V8 = 0x79");
177 /* 4123: skip next instruction if V1 != 0x23 */
179 test++;
180 c.registers[1] = 0x45;
181 c.pc = 0;
183 putopcode(0x4123, &c, c.pc);
184 chip8_step(&c);
185 TEST(c.pc == 4, "4123: skip next instruction, V1 != 0x23");
188 /* 5210: skip next instruction if V2 = V1 */
190 test++;
191 c.registers[2] = 0x69;
192 c.registers[1] = c.registers[2];
193 c.pc = 0;
195 putopcode(0x5210, &c, c.pc);
196 chip8_step(&c);
197 TEST(c.pc == 4, "5210: skip next instruction, V2 = V1");
200 /* 6456: set V4 = 0x56 */
202 test++;
204 putopcode(0x6456, &c, c.pc);
205 chip8_step(&c);
206 TEST(c.registers[4] == 0x56, "6456: set V4 = 0x56");
209 /* 7789: set V7 = V7 + 0x89 */
211 test++;
212 c.registers[7] = 0x0;
214 putopcode(0x7789, &c, c.pc);
215 chip8_step(&c);
216 TEST(c.registers[7] == 0x89, "7789: set V7 = 0x89");
219 /* 8980: set V9 = V8 */
221 test++;
222 c.registers[8] = 0x98;
224 putopcode(0x8980, &c, c.pc);
225 chip8_step(&c);
226 TEST(c.registers[9] == c.registers[8], "8980: set V9 = V8");
229 /* 8981: set V9 = V9 OR V8 */
231 test++;
232 c.registers[9] = 0x32;
233 c.registers[8] = 0x58;
235 putopcode(0x8981, &c, c.pc);
236 chip8_step(&c);
237 TEST(c.registers[9] == 0x7a, "8981: set V9 = V9 OR V8");
240 /* 8982: set V9 = V9 AND V8 */
242 test++;
243 c.registers[9] = 0x32;
244 c.registers[8] = 0x58;
246 putopcode(0x8982, &c, c.pc);
247 chip8_step(&c);
248 TEST(c.registers[9] == 0x10, "8982: set V9 = V9 AND V8");
251 /* 8983: set V9 = V9 XOR V8 */
253 test++;
254 c.registers[9] = 0x32;
255 c.registers[8] = 0x58;
257 putopcode(0x8983, &c, c.pc);
258 chip8_step(&c);
259 TEST(c.registers[9] == 0x6a, "8983: set V9 = V9 XOR V8");
262 /* 8984: set V9 = V9 + V8, VF = carry */
264 test++;
265 c.registers[9] = 0x32;
266 c.registers[8] = 0xFA;
268 putopcode(0x8984, &c, c.pc);
269 chip8_step(&c);
270 TEST(c.registers[9] == 0x2c && c.registers[0xF] == 1,
271 "8984: set V9 = V9 + V8, VF = carry");
274 /* 8985: set V9 = V9 - V8, VF = not borrow */
276 test++;
277 c.registers[9] = 0xFA;
278 c.registers[8] = 0x32;
280 putopcode(0x8985, &c, c.pc);
281 chip8_step(&c);
282 TEST(c.registers[9] == 0xc8 && c.registers[0xF] == 1,
283 "8985: set V9 = V9 - V8, VF = not borrow");
286 /* 8986: set V9 = V9 SHR 1 */
288 test++;
289 c.registers[9] = 0xFA;
291 putopcode(0x8986, &c, c.pc);
292 chip8_step(&c);
293 TEST(c.registers[9] == 0x7D && c.registers[0xF] == 0,
294 "8986: set V9 = V9 SHR 1");
297 /* 8987: set V9 = V8 - V9, VF = not borrow */
299 test++;
300 c.registers[9] = 0x32;
301 c.registers[8] = 0xFA;
303 putopcode(0x8987, &c, c.pc);
304 chip8_step(&c);
305 TEST(c.registers[9] == 0xc8 && c.registers[0xF] == 1,
306 "8987: set V9 = V8 - V9, VF = not borrow");
309 /* 898E: V9 = V9 SHL 1 */
311 test++;
312 c.registers[9] = 0x32;
314 putopcode(0x898E, &c, c.pc);
315 chip8_step(&c);
316 TEST(c.registers[9] == 0x64 && c.registers[0xF] == 0,
317 "898E: set V9 = V9 SHL 1");
320 /* 9120: skip next instruction if V1 != V2 */
322 test++;
323 c.registers[1] = 0x45;
324 c.registers[2] = 0x32;
325 c.pc = 0;
327 putopcode(0x9120, &c, c.pc);
328 chip8_step(&c);
329 TEST(c.pc == 4, "9120: skip next instruction, V1 != V2");
332 /* A123: set I to 0x123 */
334 test++;
336 putopcode(0xA123, &c, c.pc);
337 chip8_step(&c);
338 TEST(c.index == 0x123, "A123: set I to 0x123");
341 /* B345: jump to location 0x345 + V0 */
343 test++;
344 c.registers[0] = 0x12;
345 c.pc = 0;
347 putopcode(0xB345, &c, c.pc);
348 chip8_step(&c);
349 TEST(c.pc == 0x357, "B345: jump to location 0x345 + 0x12 (V0)");
352 /* E69E: skip next instruction if key with the value of V6 is pressed */
354 test++;
355 c.registers[6] = 1;
356 c.keypad[c.registers[6]] = 1;
357 c.pc = 0;
359 putopcode(0xE69E, &c, c.pc);
360 chip8_step(&c);
361 TEST(c.pc == 4, "E69E: skip next instruction, key with value of V6"
362 " is pressed");
366 * E1A1: skip next instruction if key with the value of V1 is not
367 * pressed.
370 test++;
371 c.registers[1] = 4;
372 c.keypad[c.registers[1]] = 0;
373 c.pc = 0;
375 putopcode(0xE1A1, &c, c.pc);
376 chip8_step(&c);
377 TEST(c.pc == 4, "E1A1: skip next instruction, "
378 "key with value of V1 is not pressed");
381 /* F507: set V5 = delay timer value */
383 test++;
384 c.pc = 0;
385 c.delay_timer = 4;
387 putopcode(0xF507, &c, c.pc);
388 chip8_step(&c);
389 TEST(c.pc == 2 && c.registers[5] == 4,
390 "F507: set V5 to delay timer value");
393 /* F20A: wait for a key press, store the value of the key in V2 */
395 test++;
396 c.pc = 0;
397 (void)memset(c.keypad, 0, sizeof c.keypad);
398 c.keypad[0] = 1;
400 putopcode(0xF20A, &c, c.pc);
401 chip8_step(&c);
402 TEST(c.pc == 2 && c.registers[2] == 0,
403 "F20A: key 'x' is pressed, V2 = 0");
406 /* F515: set delay timer = V5 */
408 test++;
409 c.pc = 0;
410 c.registers[5] = 5;
412 putopcode(0xF515, &c, c.pc);
413 chip8_step(&c);
414 TEST(c.pc == 2 && c.delay_timer == 5,
415 "F515: set delay timer = V5");
418 /* F718: set sound timer = V7 */
420 test++;
421 c.pc = 0;
422 c.registers[7] = 7;
424 putopcode(0xF718, &c, c.pc);
425 chip8_step(&c);
426 TEST(c.pc == 2 && c.sound_timer == 7,
427 "F718: set sound timer = V7");
430 /* F01E: set I = I + V0 */
432 uint16_t oindex = c.index;
434 test++;
435 c.pc = 0;
436 c.registers[0] = 1;
438 putopcode(0xF01E, &c, c.pc);
439 chip8_step(&c);
440 TEST(c.pc == 2 && c.index == oindex + 1,
441 "F01E: set I = I + V0");
444 /* F929: set I to location of sprite for digit V9 */
446 test++;
447 c.pc = 0;
448 c.registers[9] = 2;
450 putopcode(0xF929, &c, c.pc);
451 chip8_step(&c);
452 TEST(c.pc == 2 && c.index == 0x5A,
453 "F929: set I to location of sprite of '2'");
457 * F333: store BCD representation of V3 in memory at locations I, I+1
458 * and I+2
461 test++;
462 c.pc = 0;
463 c.registers[3] = 231;
465 putopcode(0xF333, &c, c.pc);
466 chip8_step(&c);
467 TEST(c.pc == 2 && c.memory[c.index + 2] == 1 &&
468 c.memory[c.index + 1] == 3 && c.memory[c.index] == 2,
469 "F333: store BCD representation of V3 in memory locations "
470 "I, I+1, I+2");
473 /* F255: store registers V0-V2 in memory starting from I */
475 int res;
477 test++;
478 c.pc = 0;
479 c.registers[0] = 0;
480 c.registers[1] = 1;
481 c.registers[2] = 2;
483 putopcode(0xF255, &c, c.pc);
484 chip8_step(&c);
486 res = 1;
487 for (uint8_t r = 0; r <= 2 && res != 0; r++) {
488 if (c.memory[c.index + r] != c.registers[r]) {
489 res = 0;
492 TEST(c.pc == 2 && res == 1,
493 "F255: store registers V0-V2 in memory starting from "
494 "location I");
497 /* F165: read registers V0-V1 in memory starting from I */
499 int res;
501 test++;
502 c.pc = 0;
503 c.registers[1] = 10;
504 c.registers[2] = 20;
506 putopcode(0xF165, &c, c.pc);
507 chip8_step(&c);
509 res = 1;
510 for (uint8_t r = 0; r <= 1 && res != 0; r++) {
511 if (c.memory[c.index + r] != c.registers[r]) {
512 res = 0;
515 TEST(c.pc == 2 && res == 1,
516 "F165: read registers V0-V1 in memory starting from "
517 "location I");
520 (void)printf("[==========] %d test cases ran.\n", test);
521 (void)printf("[ PASSED ] %d tests.\n", count_pass);
522 (void)printf("[ FAILED ] %d tests.\n", count_fail);
523 teardown();
524 return (0);