8

a CHIP-8 emulator
Log | Files | Refs | README

8.c (5382B)


      1 #include <err.h>
      2 #include <fcntl.h>
      3 #include <limits.h>
      4 #include <stdint.h>
      5 #include <stdio.h>
      6 #include <stdlib.h>
      7 #include <string.h>
      8 #include <unistd.h>
      9 
     10 #include <sys/types.h>
     11 #include <sys/stat.h>
     12 
     13 #include "av.h"
     14 
     15 #define START 0x200
     16 
     17 uint16_t opcode;
     18 uint8_t *mem;
     19 uint8_t V[16];
     20 uint16_t I;
     21 uint16_t pc;
     22 uint8_t scene[32*64];
     23 uint8_t delaytmr;
     24 uint8_t soundtmr;
     25 uint16_t stack[16];
     26 uint16_t *sp = stack;
     27 uint8_t keys[16];
     28 
     29 uint8_t fnt[80] =
     30 {
     31 	0xF0, 0x90, 0x90, 0x90, 0xF0, //0
     32 	0x20, 0x60, 0x20, 0x20, 0x70, //1
     33 	0xF0, 0x10, 0xF0, 0x80, 0xF0, //2
     34 	0xF0, 0x10, 0xF0, 0x10, 0xF0, //3
     35 	0x90, 0x90, 0xF0, 0x10, 0x10, //4
     36 	0xF0, 0x80, 0xF0, 0x10, 0xF0, //5
     37 	0xF0, 0x80, 0xF0, 0x90, 0xF0, //6
     38 	0xF0, 0x10, 0x20, 0x40, 0x40, //7
     39 	0xF0, 0x90, 0xF0, 0x90, 0xF0, //8
     40 	0xF0, 0x90, 0xF0, 0x10, 0xF0, //9
     41 	0xF0, 0x90, 0xF0, 0x90, 0x90, //A
     42 	0xE0, 0x90, 0xE0, 0x90, 0xE0, //B
     43 	0xF0, 0x80, 0x80, 0x80, 0xF0, //C
     44 	0xE0, 0x90, 0x90, 0x90, 0xE0, //D
     45 	0xF0, 0x80, 0xF0, 0x80, 0xF0, //E
     46 	0xF0, 0x80, 0xF0, 0x80, 0x80  //F
     47 };
     48 
     49 static void
     50 init(int fd, size_t sz)
     51 {
     52 	size_t r;
     53 
     54 	mem = malloc(4096);
     55 	if (mem == NULL)
     56 		err(1, "malloc failed");
     57 	memset(mem, 0, 4096);
     58 
     59 	pc = START;
     60 	memcpy(mem, fnt, 80);
     61 	while ((r = read(fd, mem + pc, sz)) != -1) {
     62 		sz -= r;
     63 		if (!sz)
     64 			break;
     65 	}
     66 	if (r == -1)
     67 		err(1, "read failed");
     68 }
     69 
     70 void
     71 predraw(unsigned short n, unsigned short x, unsigned y)
     72 {
     73 	uint16_t px;
     74 
     75 	V[0xF] = 0;
     76 	for (int yy = 0; yy < n; ++yy) {
     77 		px = mem[I + yy];
     78 		for (int xx = 0; xx < 8; ++xx) {
     79 			if ((px & (0x80 >> xx)) != 0) {
     80 				if (scene[(V[x] + xx + ((V[y] + yy) * 64))] == 1)
     81 					V[0xF] = 1;
     82 				scene[V[x] + xx + ((V[y] + yy) * 64)] ^= 1;
     83 			}
     84 		}
     85 	}
     86 	draw(scene);
     87 }
     88 
     89 static void
     90 execute(void)
     91 {
     92 	unsigned short x, y, c, n;
     93 
     94 	switch (opcode & 0xF000) {
     95 	case 0x0000:
     96 		switch (opcode & 0x0FFF) {
     97 		case 0xe0:
     98 			memset(scene, 0, 2048);
     99 			pc += 2;
    100 			return;
    101 		case 0xee:
    102 			pc = *sp--;
    103 			pc += 2;
    104 			return;
    105 		}
    106 	case 0x1000:
    107 		pc = opcode & 0x0FFF;
    108 		return;
    109 	case 0x2000:
    110 		*++sp = pc;
    111 		pc = opcode & 0x0FFF;
    112 		return;
    113 	case 0x3000:
    114 		x = (opcode & 0x0F00) >> 8;
    115 		c = opcode & 0x00FF;
    116 		if (V[x] == c)
    117 			pc += 2;
    118 		pc += 2;
    119 		return;
    120 	case 0x4000:
    121 		x = (opcode & 0x0F00) >> 8;
    122 		c = opcode & 0x00FF;
    123 		if (V[x] != c)
    124 			pc += 2;
    125 		pc += 2;
    126 		return;
    127 	case 0x5000:
    128 		x = (opcode & 0x0F00) >> 8;
    129 		y = (opcode & 0x00F0) >> 4;
    130 		if (V[x] == V[y])
    131 			pc += 2;
    132 		pc += 2;
    133 		return;
    134 	case 0x6000:
    135 		x = (opcode & 0x0F00) >> 8;
    136 		c = opcode & 0x00FF;
    137 		V[x] = c;
    138 		pc += 2;
    139 		return;
    140 	case 0x7000:
    141 		x = (opcode & 0x0F00) >> 8;
    142 		c = opcode & 0x00FF;
    143 		V[x] += c;
    144 		pc += 2;
    145 		return;
    146 	case 0x8000:
    147 		x = (opcode & 0x0F00) >> 8;
    148 		y = (opcode & 0x00F0) >> 4;
    149 		pc += 2;
    150 		switch(opcode & 0x000F) {
    151 		case 0x0000:
    152 			V[x] = V[y];
    153 			return;
    154 		case 0x0001:
    155 			V[x] |= V[y];
    156 			return;
    157 		case 0x0002:
    158 			V[x] &= V[y];
    159 			return;
    160 		case 0x0003:
    161 			V[x] ^= V[y];
    162 			return;
    163 		case 0x0004:
    164 			V[0xF] = 0;
    165 			if (V[y] > CHAR_MAX - V[x])
    166 				V[0xF] = 1;
    167 			V[x] += V[y];
    168 			return;
    169 		case 0x0005:
    170 			V[0xF] = 0;
    171 			if (V[y] < V[x])
    172 				V[0xF] = 1;
    173 			V[x] -= V[y];
    174 			return;
    175 		case 0x0006:
    176 			V[0xF] = V[x] & 0x01;
    177 			V[x] >>= 1;
    178 			return;
    179 		case 0x0007:
    180 			V[0xF] = 0;
    181 			if (V[x] < V[y])
    182 				V[0xF] = 1;
    183 			V[x] = V[y] - V[x];
    184 			return;
    185 		case 0x000E:
    186 			V[0xF] = (V[x] >> 7) & 0x01;
    187 			V[x] <<= 1;
    188 			return;
    189 		default:
    190 			goto err;
    191 		}
    192 	case 0x9000:
    193 		x = (opcode & 0x0F00) >> 8;
    194 		y = (opcode & 0x00F0) >> 4;
    195 		if (V[x] != V[y])
    196 			pc += 2;
    197 		pc += 2;
    198 		return;
    199 	case 0xA000:
    200 		I = opcode & 0x0FFF;
    201 		pc += 2;
    202 		return;
    203 	case 0xB000:
    204 		pc = V[0] + (opcode & 0x0FFF);
    205 		return;
    206 	case 0xC000:
    207 		x = (opcode & 0x0F00) >> 8;
    208 		c = (opcode & 0x00FF);
    209 		V[x] = (rand() % 256) & c;
    210 		pc += 2;
    211 		return;
    212 	case 0xD000:
    213 		n = (opcode & 0x00F);
    214 		x = (opcode & 0x0F00) >> 8;
    215 		y = (opcode & 0x00F0) >> 4;
    216 		predraw(n, x, y);
    217 		pc += 2;
    218 		return;
    219 	case 0xE000:
    220 		x = (opcode & 0x0F00) >> 8;
    221 		pc += 2;
    222 		switch (opcode & 0x00FF) {
    223 		case 0x009E:
    224 			if (key[V[x]])
    225 				pc += 2;
    226 			return;
    227 		case 0x00A1:
    228 			if (!key[V[x]])
    229 				pc += 2;
    230 			return;
    231 		default:
    232 			goto err;
    233 		}
    234 	case 0xF000:
    235 		x = (opcode & 0x0F00) >> 8;
    236 		pc += 2;
    237 		switch (opcode & 0x00FF) {
    238 		case 0x0007:
    239 			V[x] = delaytmr;
    240 			return;
    241 		case 0x000A:
    242 			for (int i = 0; i < 16; ++i)
    243 				if (key[i]) {
    244 					V[x] = i;
    245 					return;
    246 				}
    247 			pc -= 2;
    248 			return;
    249 		case 0x0015:
    250 			delaytmr = V[x];
    251 			return;
    252 		case 0x0018:
    253 			soundtmr = V[x];
    254 			return;
    255 		case 0x001E:
    256 			I += V[x];
    257 			return;
    258 		case 0x0029:
    259 			I = V[x] * 5;
    260 			return;
    261 		case 0x0033:
    262 			mem[I] = (V[x] % 1000) / 100;
    263 			mem[I + 1] = (V[x] % 100) / 10;
    264 			mem[I + 2] = V[x] % 10;
    265 			return;
    266 		case 0x0055:
    267 			memcpy(mem + I, V, x+1);
    268 			return;
    269 		case 0x0065:
    270 			memcpy(V, mem + I, x+1);
    271 			return;
    272 		default:
    273 			goto err;
    274 		}
    275 	default:
    276 		goto err;
    277 	}
    278 err:
    279 	fprintf(stderr, "Unknown opcode: 0x%X\n", opcode);
    280 }
    281 
    282 static void
    283 die(void)
    284 {
    285 	sdlquit();
    286 	free(mem);
    287 	exit(0);
    288 }
    289 
    290 static void
    291 cycle()
    292 {
    293 	opcode = mem[pc] << 8 | mem[pc + 1];
    294 	execute();
    295 	handleev();
    296 	if (quit)
    297 		die();
    298 	usleep(1500);
    299 }
    300 
    301 static void
    302 usage()
    303 {
    304 	fprintf(stderr, "usage: 8 file.rom\n");
    305 	exit(1);
    306 }
    307 
    308 int
    309 main(int argc, char **argv)
    310 {
    311 	struct stat st;
    312 	int fd;
    313 
    314 	if (argc < 2)
    315 		usage();
    316 
    317 	if (stat(argv[1], &st) != 0)
    318 		err(1, "stat failed");
    319 
    320 	if ((fd = open(argv[1], O_RDONLY)) == -1)
    321 		err(1, "open failed");
    322 
    323 	sdlinit();
    324 	init(fd, st.st_size);
    325 	for (;;)
    326 		cycle();
    327 	return 0;
    328 }