upload of the files for pgb
This commit is contained in:
commit
335839205a
10 changed files with 2905 additions and 0 deletions
10
.clangd
Normal file
10
.clangd
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
CompileFlags:
|
||||
Add:
|
||||
- -x
|
||||
- c
|
||||
- -Wall
|
||||
- -Wextra
|
||||
- -Werror
|
||||
- -Wpedantic
|
||||
- -std=c99
|
||||
- -Wno-empty-translation-unit
|
||||
31
Makefile
Normal file
31
Makefile
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
CC = cc
|
||||
CFLAGS = -Wall -Wextra -Wpedantic -Werror -std=c99 -lX11
|
||||
|
||||
SRCDIR = src
|
||||
OBJDIR = obj
|
||||
SRC = $(wildcard $(SRCDIR)/*.c)
|
||||
OBJ = $(SRC:$(SRCDIR)/%.c=$(OBJDIR)/%.o)
|
||||
|
||||
TARGET = pgb
|
||||
|
||||
debug: CFLAGS += -g3 -fsanitize=address
|
||||
debug: all
|
||||
|
||||
release: CFLAGS += -O3 -s
|
||||
release: all
|
||||
|
||||
all: $(OBJDIR) $(TARGET)
|
||||
|
||||
$(TARGET): $(OBJ)
|
||||
$(CC) $(CFLAGS) -o $@ $^
|
||||
|
||||
$(OBJDIR):
|
||||
mkdir -p $(OBJDIR)
|
||||
|
||||
$(OBJDIR)/%.o: $(SRCDIR)/%.c
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
clean:
|
||||
rm -rf $(OBJDIR) $(TARGET)
|
||||
|
||||
.PHONY: clean all debug release
|
||||
0
README.md
Normal file
0
README.md
Normal file
BIN
pgb
Executable file
BIN
pgb
Executable file
Binary file not shown.
45
src/main.c
Normal file
45
src/main.c
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
#include "pgb.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#define GB_RATE 59.73
|
||||
#define CLOCKS_PER_FRAME 70224
|
||||
#define TIME_TO_SLEEP (CLOCKS_PER_SEC / GB_RATE)
|
||||
|
||||
int main(const int argc, const char **argv) {
|
||||
create_window();
|
||||
if (argc > 1) {
|
||||
const char *gamerom = NULL;
|
||||
const char *logfile = NULL;
|
||||
int i;
|
||||
for (i = 1; i < argc; i++) {
|
||||
if (strcmp(argv[i], "--file") == 0) {
|
||||
gamerom = argv[++i];
|
||||
} else if (strcmp(argv[i], "--log") == 0) {
|
||||
logfile = argv[++i];
|
||||
}
|
||||
}
|
||||
if (gamerom != NULL) {
|
||||
cpu_init(gamerom, logfile);
|
||||
int timer = time(NULL);
|
||||
while (1) {
|
||||
int i;
|
||||
int start = clock();
|
||||
for (i = 0; i < CLOCKS_PER_FRAME; i++) {
|
||||
cpu_cycle();
|
||||
ppu_dot();
|
||||
timer_cycle();
|
||||
}
|
||||
while ((clock() - start) < TIME_TO_SLEEP) {
|
||||
}
|
||||
if (time(NULL) - timer >= 1) {
|
||||
timer = time(NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
close_window();
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
47
src/pgb.h
Normal file
47
src/pgb.h
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
typedef unsigned char u8;
|
||||
typedef signed char s8;
|
||||
typedef unsigned short u16;
|
||||
typedef signed char s16;
|
||||
|
||||
typedef enum R8 { R8_A, R8_F, R8_B, R8_C, R8_D, R8_E, R8_H, R8_L } R8;
|
||||
typedef enum R16 { R16_AF, R16_BC, R16_DE, R16_HL, R16_SP, R16_PC } R16;
|
||||
typedef enum RFLAG {
|
||||
NOFLAG0,
|
||||
NOFLAG1,
|
||||
NOFLAG2,
|
||||
NOFLAG3,
|
||||
FLAG_C,
|
||||
FLAG_H,
|
||||
FLAG_N,
|
||||
FLAG_Z
|
||||
} RFLAG;
|
||||
|
||||
typedef enum INTERRUPT {
|
||||
INT_VBLANK,
|
||||
INT_LCD,
|
||||
INT_TIMER,
|
||||
INT_SERIAL,
|
||||
INT_JOYPAD
|
||||
} INTERRUPT;
|
||||
|
||||
void lock_oam(void);
|
||||
void unlock_oam(void);
|
||||
void lock_vram(void);
|
||||
void unlock_vram(void);
|
||||
|
||||
u8 mread8_external(const u16 addr);
|
||||
u16 mread16_external(const u16 addr);
|
||||
void mwrite8_external(const u16 addr, const u8 val);
|
||||
void mwrite16_external(const u16 addr, const u16 val);
|
||||
|
||||
void cpu_init(const char *gamerom, const char *logfile);
|
||||
void cpu_cycle(void);
|
||||
void create_interrupt(const INTERRUPT interrupt);
|
||||
|
||||
void ppu_dot(void);
|
||||
|
||||
void timer_cycle(void);
|
||||
|
||||
void create_window(void);
|
||||
void draw_pixel(u8 x, u8 y, u8 color);
|
||||
void close_window(void);
|
||||
67
src/ppu.c
Normal file
67
src/ppu.c
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
#include "pgb.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
static u16 dot;
|
||||
static u8 scanline;
|
||||
static u8 x;
|
||||
static u8 delay;
|
||||
|
||||
#define get_lcdc(bit) ((mread8_external(0xFF40) >> bit) & 1)
|
||||
|
||||
void fetch_bg_pixel(u8 display_x, u8 display_y) {
|
||||
u8 internal_x = mread8_external(0xFF43) + display_x;
|
||||
u8 internal_y = mread8_external(0xFF42) + display_y;
|
||||
u16 tile_addr_offset =
|
||||
mread8_external((get_lcdc(3) ? 0x9C00 : 0x9800) + (u16)(internal_x / 8) +
|
||||
((u16)(internal_y / 8)) * 32) *
|
||||
16;
|
||||
u16 tile_addr = get_lcdc(4) ? (0x8000 + tile_addr_offset)
|
||||
: (0x9000 + (s16)tile_addr_offset);
|
||||
u8 tile_x = internal_x % 8;
|
||||
u8 tile_y = internal_y % 8;
|
||||
u16 tile_data = mread16_external(tile_addr + tile_y * 2);
|
||||
if (tile_y < 3) {
|
||||
u16 addr = 0x8000 + (mread8_external((get_lcdc(3) ? 0x9C00 : 0x9800) +
|
||||
(u16)internal_x / 8 +
|
||||
(u16)((internal_y + 3) / 8) * 32) *
|
||||
16);
|
||||
if (mread16_external(addr + (tile_y + 3) * 2) != tile_data && get_lcdc(4)) {
|
||||
printf("(u16)(%d) (u16)(%d)\n", (internal_y) / 8, (internal_y + 3) / 8);
|
||||
}
|
||||
}
|
||||
u8 color = (tile_data >> abs(tile_x - 7)) & 1;
|
||||
color += ((tile_data >> abs(tile_x - 15)) & 1) * 2;
|
||||
draw_pixel(display_x, display_y, color);
|
||||
}
|
||||
|
||||
void ppu_dot(void) {
|
||||
if (dot == 0) {
|
||||
lock_oam();
|
||||
x = 0;
|
||||
delay = 0;
|
||||
} else if (dot == 456) {
|
||||
dot = -1;
|
||||
scanline++;
|
||||
if (scanline == 144) {
|
||||
create_interrupt(INT_VBLANK);
|
||||
}
|
||||
if (scanline == 154) {
|
||||
scanline = 0;
|
||||
}
|
||||
}
|
||||
if (dot >= 80 && x < 160) {
|
||||
if (delay == 0) {
|
||||
unlock_vram();
|
||||
fetch_bg_pixel(x, scanline);
|
||||
x++;
|
||||
lock_vram();
|
||||
} else {
|
||||
delay--;
|
||||
}
|
||||
} else if (x == 160) {
|
||||
unlock_vram();
|
||||
unlock_oam();
|
||||
}
|
||||
dot++;
|
||||
}
|
||||
37
src/timer.c
Normal file
37
src/timer.c
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
#include "pgb.h"
|
||||
|
||||
static u16 counter = 0;
|
||||
|
||||
static u16 get_cycles_to_count(void) {
|
||||
switch (mread8_external(0xFF07) & 3) {
|
||||
case 0:
|
||||
return 1024;
|
||||
break;
|
||||
case 1:
|
||||
return 16;
|
||||
break;
|
||||
case 2:
|
||||
return 64;
|
||||
break;
|
||||
case 3:
|
||||
return 256;
|
||||
break;
|
||||
}
|
||||
return 1024;
|
||||
}
|
||||
|
||||
void timer_cycle(void) {
|
||||
if (mread8_external(0xFF07) & 4) {
|
||||
if (counter < get_cycles_to_count()) {
|
||||
counter++;
|
||||
} else {
|
||||
counter = 0;
|
||||
if (mread8_external(0xFF05) == 0xFF) {
|
||||
mwrite8_external(0xFF05, mread8_external(0xFF06));
|
||||
create_interrupt(INT_TIMER);
|
||||
} else {
|
||||
mwrite8_external(0xFF05, mread8_external(0xFF05) + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
53
src/window.c
Normal file
53
src/window.c
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
#include "pgb.h"
|
||||
#include <X11/Xatom.h>
|
||||
#include <X11/Xlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
static Display *display;
|
||||
static Window window;
|
||||
static int screen;
|
||||
|
||||
void create_window(void) {
|
||||
display = XOpenDisplay(NULL);
|
||||
if (display == NULL) {
|
||||
fprintf(stderr, "Cannot open display\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
screen = DefaultScreen(display);
|
||||
|
||||
window = XCreateSimpleWindow(display, RootWindow(display, screen), 10, 10,
|
||||
320, 288, 1, BlackPixel(display, screen),
|
||||
WhitePixel(display, screen));
|
||||
|
||||
XStoreName(display, window, "PGB");
|
||||
XSelectInput(display, window, ExposureMask | KeyPressMask);
|
||||
XMapWindow(display, window);
|
||||
}
|
||||
|
||||
void draw_pixel(u8 x, u8 y, u8 color) {
|
||||
unsigned long real_color = 0xFFFFFFFF;
|
||||
switch (color) {
|
||||
case 0:
|
||||
real_color = 0xFFFFFFFF;
|
||||
break;
|
||||
case 1:
|
||||
real_color = 0xAAAAAAAA;
|
||||
break;
|
||||
case 2:
|
||||
real_color = 0x55555555;
|
||||
break;
|
||||
case 3:
|
||||
real_color = 0x00000000;
|
||||
break;
|
||||
}
|
||||
XSetForeground(display, DefaultGC(display, screen), real_color);
|
||||
XFillRectangle(display, window, DefaultGC(display, screen), x * 2, y * 2, 2,
|
||||
2);
|
||||
}
|
||||
|
||||
void close_window(void) {
|
||||
XDestroyWindow(display, window);
|
||||
XCloseDisplay(display);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue