commit 9d18655339b743b72bd82f8d93c905e66dbac4bd
parent 9fe1ca723978ede2fb6785443ffa3a5a08dab310
Author: Naveen Narayanan <zerous@nocebo.space>
Date: Sun, 21 Jul 2024 19:04:52 +0200
Use SDL
Diffstat:
M | 8.c | | | 257 | +++++++++++++++++++++++++++++++++++++++++++++---------------------------------- |
M | Makefile | | | 20 | ++++++++++++++++++-- |
A | av.c | | | 151 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | av.h | | | 15 | +++++++++++++++ |
4 files changed, 330 insertions(+), 113 deletions(-)
diff --git a/8.c b/8.c
@@ -1,6 +1,7 @@
#include <err.h>
#include <fcntl.h>
#include <limits.h>
+#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -9,22 +10,26 @@
#include <sys/types.h>
#include <sys/stat.h>
+#include "av.h"
+
#define BUFSZ 256
+#define START 0x200
-unsigned short opcode;
-unsigned char mem[4096];
-unsigned char V[16];
-unsigned short I;
-unsigned short pc;
-unsigned char gfx[64 * 32];
-unsigned char delaytmr;
-unsigned char soundtmr;
-unsigned short stack[16];
-unsigned short* sp;
-unsigned char keys[16];
-unsigned char buf[BUFSZ];
+uint16_t opcode;
+uint8_t *mem;
+uint8_t V[16];
+uint16_t I;
+uint16_t pc;
+uint8_t scene[32*64];
+uint8_t delaytmr;
+uint8_t soundtmr;
+uint16_t stack[16];
+uint16_t *sp = stack;
+uint8_t keys[16];
+uint8_t buf[BUFSZ];
+uint8_t bit[8];
-unsigned char fnt[80] =
+uint8_t fnt[80] =
{
0xF0, 0x90, 0x90, 0x90, 0xF0, //0
0x20, 0x60, 0x20, 0x20, 0x70, //1
@@ -45,111 +50,107 @@ unsigned char fnt[80] =
};
static void
-init()
+init(int fd, size_t sz)
{
- pc = 0x200;
- opcode = 0;
- I = 0;
- sp = stack;
-
- for (int i = 0; i < 80; ++i)
- mem[i] = fnt[i];
-
- for (int i = 0; i < BUFSZ; ++i)
- mem[i + 512] = buf[i];
-}
+ size_t r, t;
-static void
-clrscr()
-{
-}
-
-static short
-sprite()
-{
- /* return address of sprite */
- return 0;
-}
+ t = sz;
+ mem = malloc(4096);
+ if (mem == NULL)
+ err(1, "malloc failed");
+ memset(mem, 0, 4096);
-static void
-draw()
-{
-}
-
-static int
-key()
-{
- /* return pressed key */
- return 0;
+ pc = START;
+ memcpy(mem, fnt, 80);
+ while ((r = read(fd, mem + pc, sz)) != -1) {
+ sz -= r;
+ if (!sz)
+ break;
+ }
+ if (r == -1)
+ err(1, "read failed");
}
-static int
-waitkey()
+void
+predraw(unsigned short n, unsigned short x, unsigned y)
{
- /* block until keypress and return it */
- return 0;
-}
+ uint16_t px;
-static void
-bcd()
-{
+ V[0xF] = 0;
+ for (int yy = 0; yy < n; ++yy) {
+ px = mem[I + yy];
+ for (int xx = 0; xx < 8; ++xx) {
+ if ((px & (0x80 >> xx)) != 0) {
+ if (scene[(V[x] + xx + ((V[y] + yy) * 64))] == 1)
+ V[0xF] = 1;
+ scene[V[x] + xx + ((V[y] + yy) * 64)] ^= 1;
+ }
+ }
+ }
+ draw(scene);
}
static void
-execute()
+execute(void)
{
- int x, y, c;
+ unsigned short x, y, c, n;
switch (opcode & 0xF000) {
case 0x0000:
- switch (opcode) {
- case 0x00E0:
- clrscr();
+ switch (opcode & 0x0FFF) {
+ case 0xe0:
+ //fprintf(stderr,"[OK] 0x%X: 00E0\n", opcode);
+ memset(scene, 0, 2048);
pc += 2;
- case 0x00EE:
- if (sp > stack) {
- pc = *sp;
- --sp;
- }
return;
- default:
- fprintf(stderr, "machine code routine\n");
- pc += 2;
+ case 0xee:
+ //fprintf(stderr,"[OK] 0x%X: 00EE\n", opcode);
+ pc = *sp--;
+ pc += 2;
return;
}
case 0x1000:
+ //fprintf(stderr,"[OK] 0x%X: 1NNN\n", opcode);
pc = opcode & 0x0FFF;
return;
case 0x2000:
- *sp = pc;
- ++sp;
+ //fprintf(stderr,"[OK] 0x%X: 2NNN\n", opcode);
+ *++sp = pc;
pc = opcode & 0x0FFF;
return;
case 0x3000:
+ //fprintf(stderr,"[OK] 0x%X: 3XNN\n", opcode);
x = (opcode & 0x0F00) >> 8;
c = opcode & 0x00FF;
if (V[x] == c)
- pc += 4;
+ pc += 2;
+ pc += 2;
return;
case 0x4000:
+ //fprintf(stderr,"[OK] 0x%X: 4XNN\n", opcode);
x = (opcode & 0x0F00) >> 8;
c = opcode & 0x00FF;
if (V[x] != c)
- pc += 4;
+ pc += 2;
+ pc += 2;
return;
case 0x5000:
+ //fprintf(stderr,"[OK] 0x%X: 5XY0\n", opcode);
x = (opcode & 0x0F00) >> 8;
y = (opcode & 0x00F0) >> 4;
if (V[x] == V[y])
- pc += 4;
+ pc += 2;
+ pc += 2;
return;
case 0x6000:
+ //fprintf(stderr,"[OK] 0x%X: 6XNN\n", opcode);
x = (opcode & 0x0F00) >> 8;
c = opcode & 0x00FF;
V[x] = c;
pc += 2;
return;
case 0x7000:
+ //fprintf(stderr,"[OK] 0x%X: 7XNN\n", opcode);
x = (opcode & 0x0F00) >> 8;
c = opcode & 0x00FF;
V[x] += c;
@@ -161,71 +162,88 @@ execute()
pc += 2;
switch(opcode & 0x000F) {
case 0x0000:
+ //fprintf(stderr,"[OK] 0x%X: 8XY0\n", opcode);
V[x] = V[y];
return;
case 0x0001:
+ //fprintf(stderr,"[OK] 0x%X: 8XY1\n", opcode);
V[x] |= V[y];
return;
case 0x0002:
+ //fprintf(stderr,"[OK] 0x%X: 8XY2\n", opcode);
V[x] &= V[y];
return;
case 0x0003:
+ //fprintf(stderr,"[OK] 0x%X: 8XY3\n", opcode);
V[x] ^= V[y];
return;
case 0x0004:
+ //fprintf(stderr,"[OK] 0x%X: 8XY4\n", opcode);
V[0xF] = 0;
if (V[y] > CHAR_MAX - V[x])
V[0xF] = 1;
V[x] += V[y];
return;
case 0x0005:
+ //fprintf(stderr,"[OK] 0x%X: 8XY5\n", opcode);
V[0xF] = 0;
- if (V[y] > V[x])
+ if (V[y] < V[x])
V[0xF] = 1;
V[x] -= V[y];
return;
case 0x0006:
+ //fprintf(stderr,"[OK] 0x%X: 8XY6\n", opcode);
V[0xF] = V[x] & 0x01;
V[x] >>= 1;
return;
case 0x0007:
- V[0xF] = 1;
- if (V[x] > V[y])
- V[0xF] = 0;
+ //fprintf(stderr,"[OK] 0x%X: 8XY7\n", opcode);
+ V[0xF] = 0;
+ if (V[x] < V[y])
+ V[0xF] = 1;
V[x] = V[y] - V[x];
return;
case 0x000E:
- V[0xF] = V[x] & 0x80;
+ //fprintf(stderr,"[OK] 0x%X: 8XYE\n", opcode);
+ V[0xF] = (V[x] >> 7) & 0x01;
V[x] <<= 1;
return;
default:
goto err;
}
case 0x9000:
+ //fprintf(stderr,"[OK] 0x%X: 9XY0\n", opcode);
+ //fprintf(stderr, "0x9000\n");
x = (opcode & 0x0F00) >> 8;
y = (opcode & 0x00F0) >> 4;
if (V[x] != V[y])
- pc += 4;
+ pc += 2;
pc += 2;
return;
case 0xA000:
+ //fprintf(stderr,"[OK] 0x%X: ANNN\n", opcode);
I = opcode & 0x0FFF;
pc += 2;
return;
case 0xB000:
+ //fprintf(stderr,"[OK] 0x%X: BNNN\n", opcode);
+ //fprintf(stderr, "0xB000\n");
pc = V[0] + (opcode & 0x0FFF);
return;
case 0xC000:
+ //fprintf(stderr,"[OK] 0x%X: CXNN\n", opcode);
x = (opcode & 0x0F00) >> 8;
c = (opcode & 0x00FF);
V[x] = (rand() % 256) & c;
+ //V[x] = 128 & c;
pc += 2;
return;
case 0xD000:
+ //fprintf(stderr,"[OK] 0x%X: DXYN\n", opcode);
+ n = (opcode & 0x00F);
x = (opcode & 0x0F00) >> 8;
y = (opcode & 0x00F0) >> 4;
- c = opcode & 0x000F;
- draw(V[x], V[y], c);
+ predraw(n, x, y);
pc += 2;
return;
case 0xE000:
@@ -233,12 +251,14 @@ execute()
pc += 2;
switch (opcode & 0x00FF) {
case 0x009E:
- if (key() == V[x])
- pc += 4;
+ //fprintf(stderr,"[OK] 0x%X: EX9E\n", opcode);
+ if (key[V[x]])
+ pc += 2;
return;
case 0x00A1:
- if (key() != V[x])
- pc += 4;
+ //fprintf(stderr,"[OK] 0x%X: EXA1\n", opcode);
+ if (!key[V[x]])
+ pc += 2;
return;
default:
goto err;
@@ -248,33 +268,47 @@ execute()
pc += 2;
switch (opcode & 0x00FF) {
case 0x0007:
+ //fprintf(stderr,"[OK] 0x%X: FX07\n", opcode);
V[x] = delaytmr;
return;
case 0x000A:
- V[x] = waitkey();
+ //fprintf(stderr,"[OK] 0x%X: FX0A\n", opcode);
+ for (int i = 0; i < 16; ++i)
+ if (key[i]) {
+ V[x] = i;
+ return;
+ }
+ pc -= 2;
return;
case 0x0015:
+ //fprintf(stderr,"[OK] 0x%X: FX15\n", opcode);
delaytmr = V[x];
return;
case 0x0018:
+ //fprintf(stderr,"[OK] 0x%X: FX18\n", opcode);
soundtmr = V[x];
return;
case 0x001E:
+ //fprintf(stderr,"[OK] 0x%X: FX1E\n", opcode);
I += V[x];
return;
case 0x0029:
- I = sprite(V[x]);
+ //fprintf(stderr,"[OK] 0x%X: FX29\n", opcode);
+ I = V[x] * 5;
return;
case 0x0033:
- bcd(x);
+ //fprintf(stderr,"[OK] 0x%X: FX33\n", opcode);
+ mem[I] = (V[x] % 1000) / 100;
+ mem[I + 1] = (V[x] % 100) / 10;
+ mem[I + 2] = V[x] % 10;
return;
case 0x0055:
- for (int i = 0; i < 16; ++i)
- mem[I + 1 + i] = V[i]; /* mem[I] shouldn't be modified */
+ //fprintf(stderr,"[OK] 0x%X: FX55\n", opcode);
+ memcpy(mem + I, V, x+1);
return;
case 0x0065:
- for (int i = 0; i < 16; ++i)
- V[i] = mem[I + 1 + i]; /* mem[I] shouldn't be modified */
+ //fprintf(stderr,"[OK] 0x%X: FX65\n", opcode);
+ memcpy(V, mem + I, x+1);
return;
default:
goto err;
@@ -287,16 +321,25 @@ err:
}
static void
+die(void)
+{
+ sdlquit();
+ free(mem);
+ exit(0);
+}
+
+static void
cycle()
{
- opcode = mem[pc] << 8 | mem[pc+1];
+ static int n;
+
+ opcode = mem[pc] << 8 | mem[pc + 1];
+ //fprintf(stderr, "opc: 0x%hx\n", opcode);
execute();
- if (delaytmr > 0)
- --delaytmr;
- if (soundtmr > 0) {
- printf("BEEP\n");
- --soundtmr;
- }
+ handleev();
+ if (quit)
+ die();
+ usleep(1500);
}
static void
@@ -310,28 +353,20 @@ int
main(int argc, char **argv)
{
struct stat st;
- int fd, n, r;
+ int fd;
if (argc < 2)
usage();
if (stat(argv[1], &st) != 0)
err(1, "stat failed");
- if (st.st_size > BUFSZ) {
- fprintf(stderr, "file too big\n");
- return 1;
- }
if ((fd = open(argv[1], O_RDONLY)) == -1)
err(1, "open failed");
- r = 0;
- while (r < st.st_size) {
- if ((n = read(fd, buf, st.st_size-r)) == -1)
- err(1, "read failed");
- r += n;
- }
-
- init();
+ sdlinit();
+ init(fd, st.st_size);
+ for (;;)
+ cycle();
return 0;
}
diff --git a/Makefile b/Makefile
@@ -1,8 +1,24 @@
+include config.mk
+
BIN = 8
-all: ${BIN}
+HEADER = av.h
+
+COMMONOBJ = \
+ 8.o \
+ av.o \
+
+all: $(BIN)
.PHONY: clean
clean:
- -rm -f ${BIN}
+ -rm -f ${BIN} av 8.o av.o
+
+.SUFFIXES: .c .o
+
+.c.o:
+ $(CC) $(CPPFLAGS) $(CFLAGS) -c $<
+
+8: $(COMMONOBJ) $(HEADER)
+ $(CC) $(CFLAGS) -o $@ $(COMMONOBJ) $(LDFLAGS) $(LDLIBS)
diff --git a/av.c b/av.c
@@ -0,0 +1,151 @@
+#include <SDL.h>
+#include <SDL_mixer.h>
+#include <err.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include "av.h"
+
+extern uint8_t delaytmr;
+extern uint8_t soundtmr;
+
+int key[16];
+int quit;
+
+static int WIDTH = 64 * 8;
+static int HEIGHT = 32 * 8;
+
+static SDL_Window *W;
+static SDL_Renderer *R;
+static Mix_Music *M;
+static SDL_TimerID T;
+
+void
+handleev(void)
+{
+ SDL_Event e;
+ const Uint8 *kstate;
+
+ quit = 0;
+ if (SDL_PollEvent(&e)) {
+ kstate = SDL_GetKeyboardState(NULL);
+ switch (e.type) {
+ case SDL_QUIT:
+ quit = 1;
+ break;
+ default:
+ if (kstate[SDL_SCANCODE_ESCAPE])
+ quit = 1;
+ key[0] = kstate[SDL_SCANCODE_1];
+ key[1] = kstate[SDL_SCANCODE_2];
+ key[2] = kstate[SDL_SCANCODE_3];
+ key[3] = kstate[SDL_SCANCODE_4];
+ key[4] = kstate[SDL_SCANCODE_Q];
+ key[5] = kstate[SDL_SCANCODE_W];
+ key[6] = kstate[SDL_SCANCODE_E];
+ key[7] = kstate[SDL_SCANCODE_R];
+ key[8] = kstate[SDL_SCANCODE_A];
+ key[9] = kstate[SDL_SCANCODE_S];
+ key[10] = kstate[SDL_SCANCODE_D];
+ key[11] = kstate[SDL_SCANCODE_F];
+ key[12] = kstate[SDL_SCANCODE_Z];
+ key[13] = kstate[SDL_SCANCODE_X];
+ key[14] = kstate[SDL_SCANCODE_C];
+ key[15] = kstate[SDL_SCANCODE_V];
+ break;
+ }
+ }
+}
+
+unsigned int
+timer(unsigned int interval, void *)
+{
+ if (delaytmr > 0)
+ delaytmr--;
+ if (soundtmr > 0) {
+ soundtmr--;
+ beep();
+ }
+ return interval;
+}
+
+void
+sdlinit(void)
+{
+ if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER) < 0)
+ errx(1, "SDL_Init failed: %s\n", SDL_GetError());
+ W = SDL_CreateWindow("SDL Tutorial", SDL_WINDOWPOS_UNDEFINED,
+ SDL_WINDOWPOS_UNDEFINED, WIDTH, HEIGHT,
+ SDL_WINDOW_SHOWN);
+ if (W == NULL)
+ errx(1, "SDL_CreateWindow failed: %s\n", SDL_GetError());
+ R = SDL_CreateRenderer(W, -1, SDL_RENDERER_ACCELERATED);
+ if (R == NULL)
+ errx(1, "SDL_CreateRenderer failed: %s\n", SDL_GetError());
+ if (Mix_OpenAudio(44100, MIX_DEFAULT_FORMAT, 2, 2048) < 0)
+ errx(1, "Mix_OpenAudio failed: %s\n", Mix_GetError());
+ M = Mix_LoadMUS("assets/beep.wav");
+ if (M == NULL)
+ errx(1, "Mix_LoadMUS failed: %s\n", Mix_GetError());
+ T = SDL_AddTimer(16, timer, NULL);
+ if (T == 0)
+ errx(1, "Mix_LoadMUS failed: %s\n", Mix_GetError());
+}
+
+int
+makesound(void *)
+{
+ unsigned int tick;
+
+ tick = SDL_GetTicks();
+ while (1) {
+ if (Mix_PlayingMusic()) {
+ if ((SDL_GetTicks() - tick) > 4) {
+ Mix_HaltMusic();
+ return 0;
+ }
+ } else {
+ Mix_PlayMusic(M, -1);
+ }
+ }
+}
+
+void
+beep(void)
+{
+ SDL_CreateThread(makesound, "BEEP", NULL);
+}
+
+int
+draw(unsigned char *scene)
+{
+ SDL_Rect r;
+
+ r.w = 8;
+ r.h = 8;
+ SDL_SetRenderDrawColor(R, 0, 0, 0, 255);
+ SDL_RenderClear(R);
+ SDL_SetRenderDrawColor(R, 255, 255, 255, 255);
+
+ for (int y = 0; y < 32; ++y)
+ for (int x = 0; x < 64; ++x)
+ if (scene[x + (y * 64)]) {
+ r.x = x * 8;
+ r.y = y * 8;
+ SDL_RenderFillRect(R, &r);
+ }
+
+ SDL_RenderPresent(R);
+ return 0;
+}
+
+void
+sdlquit(void)
+{
+ SDL_DestroyRenderer(R);
+ SDL_DestroyWindow(W);
+ Mix_FreeMusic(M);
+ SDL_RemoveTimer(T);
+ SDL_Quit();
+}
diff --git a/av.h b/av.h
@@ -0,0 +1,15 @@
+#ifndef AV_H
+#define AV_H
+
+//Include stdint.h prior to this header
+
+extern int key[16];
+extern int quit;
+
+int draw(uint8_t *);
+void sdlinit(void);
+void handleev(void);
+void sdlquit(void);
+void beep(void);
+
+#endif