init commit
This commit is contained in:
commit
95348eff2a
3 changed files with 4181 additions and 0 deletions
2
Makefile
Normal file
2
Makefile
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
all:
|
||||
$(CC) main.c -lMw -o milskoboy
|
||||
333
main.c
Normal file
333
main.c
Normal file
|
|
@ -0,0 +1,333 @@
|
|||
#define ENABLE_SOUND 0
|
||||
#define ENABLE_LCD 1
|
||||
|
||||
#include "peanut_gb.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/time.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <Mw/Milsko.h>
|
||||
|
||||
struct priv_t {
|
||||
uint8_t *rom;
|
||||
uint8_t *cart_ram;
|
||||
uint8_t *fb;
|
||||
|
||||
MwWidget *win;
|
||||
MwWidget *fb_widget;
|
||||
MwLLPixmap *px;
|
||||
};
|
||||
static struct priv_t priv;
|
||||
|
||||
int mfb_open(const char *title, int width, int height) {
|
||||
int depth, i, formatCount, convDepth = -1;
|
||||
|
||||
MwLibraryInit();
|
||||
|
||||
priv.win = MwCreateWidget(MwWindowClass, title, NULL, MwDEFAULT, MwDEFAULT,
|
||||
width, height);
|
||||
|
||||
priv.fb_widget =
|
||||
MwCreateWidget(MwImageClass, "fb", priv.win, 0, 0, width, height);
|
||||
|
||||
priv.px = NULL;
|
||||
|
||||
priv.fb = malloc(LCD_WIDTH * LCD_HEIGHT * 4);
|
||||
|
||||
// XPixmapFormatValues *formats;
|
||||
// XSetWindowAttributes windowAttributes;
|
||||
// XSizeHints sizeHints;
|
||||
// Visual *visual;
|
||||
|
||||
// s_display = XOpenDisplay(0);
|
||||
|
||||
// if (!s_display)
|
||||
// return -1;
|
||||
|
||||
// s_screen = DefaultScreen(s_display);
|
||||
// visual = DefaultVisual(s_display, s_screen);
|
||||
// formats = XListPixmapFormats(s_display, &formatCount);
|
||||
// depth = DefaultDepth(s_display, s_screen);
|
||||
// Window defaultRootWindow = DefaultRootWindow(s_display);
|
||||
|
||||
// for (i = 0; i < formatCount; ++i) {
|
||||
// if (depth == formats[i].depth) {
|
||||
// convDepth = formats[i].bits_per_pixel;
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
|
||||
// XFree(formats);
|
||||
|
||||
// // We only support 32-bit right now
|
||||
// if (convDepth != 32) {
|
||||
// XCloseDisplay(s_display);
|
||||
// return -1;
|
||||
// }
|
||||
|
||||
// int screenWidth = DisplayWidth(s_display, s_screen);
|
||||
// int screenHeight = DisplayHeight(s_display, s_screen);
|
||||
|
||||
// windowAttributes.border_pixel = BlackPixel(s_display, s_screen);
|
||||
// windowAttributes.background_pixel = BlackPixel(s_display, s_screen);
|
||||
// windowAttributes.backing_store = NotUseful;
|
||||
|
||||
// s_window = XCreateWindow(
|
||||
// s_display, defaultRootWindow, (screenWidth - width) / 2,
|
||||
// (screenHeight - height) / 2, width, height, 0, depth, InputOutput,
|
||||
// visual, CWBackPixel | CWBorderPixel | CWBackingStore,
|
||||
// &windowAttributes);
|
||||
|
||||
// if (!s_window)
|
||||
// return 0;
|
||||
|
||||
// XSelectInput(s_display, s_window, KeyPressMask | KeyReleaseMask);
|
||||
// XStoreName(s_display, s_window, title);
|
||||
|
||||
// sizeHints.flags = PPosition | PMinSize | PMaxSize;
|
||||
// sizeHints.x = 0;
|
||||
// sizeHints.y = 0;
|
||||
// sizeHints.min_width = width;
|
||||
// sizeHints.max_width = width;
|
||||
// sizeHints.min_height = height;
|
||||
// sizeHints.max_height = height;
|
||||
|
||||
// XSetWMNormalHints(s_display, s_window, &sizeHints);
|
||||
// XClearWindow(s_display, s_window);
|
||||
// XMapRaised(s_display, s_window);
|
||||
// XFlush(s_display);
|
||||
|
||||
// s_gc = DefaultGC(s_display, s_screen);
|
||||
|
||||
// s_ximage = XCreateImage(s_display, CopyFromParent, depth, ZPixmap, 0, NULL,
|
||||
// width, height, 32, width * 4);
|
||||
|
||||
// s_width = width;
|
||||
// s_height = height;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int processEvents() {
|
||||
if (!MwPending(priv.win)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
MwStep(priv.win);
|
||||
|
||||
// if (event.type != KeyPress)
|
||||
// return 0;
|
||||
|
||||
// sym = XLookupKeysym(&event.xkey, 0);
|
||||
|
||||
// if ((sym >> 8) != KEY_FUNCTION)
|
||||
// return 0;
|
||||
|
||||
// if ((sym & 0xFF) == KEY_ESC)
|
||||
// return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mfb_update(void *buffer) {
|
||||
if (processEvents() < 0)
|
||||
return -1;
|
||||
|
||||
if (priv.px == NULL) {
|
||||
priv.px = MwLoadRaw(priv.win, buffer, LCD_WIDTH, LCD_HEIGHT);
|
||||
} else {
|
||||
MwPixmapReloadRaw(priv.px, buffer);
|
||||
}
|
||||
|
||||
MwVaApply(priv.fb_widget, MwNpixmap, priv.px, NULL);
|
||||
|
||||
printf("test\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void mfb_close(void) {
|
||||
// s_ximage->data = NULL;
|
||||
// XDestroyImage(s_ximage);
|
||||
// XDestroyWindow(s_display, s_window);
|
||||
// XCloseDisplay(s_display);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a byte from the ROM file at the given address.
|
||||
*/
|
||||
uint8_t gb_rom_read(struct gb_s *gb, const uint_fast32_t addr) {
|
||||
const struct priv_t *const p = gb->direct.priv;
|
||||
return p->rom[addr];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a byte from the cartridge RAM at the given address.
|
||||
*/
|
||||
uint8_t gb_cart_ram_read(struct gb_s *gb, const uint_fast32_t addr) {
|
||||
const struct priv_t *const p = gb->direct.priv;
|
||||
return p->cart_ram[addr];
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a given byte to the cartridge RAM at the given address.
|
||||
*/
|
||||
void gb_cart_ram_write(struct gb_s *gb, const uint_fast32_t addr,
|
||||
const uint8_t val) {
|
||||
const struct priv_t *const p = gb->direct.priv;
|
||||
p->cart_ram[addr] = val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a pointer to the allocated space containing the ROM. Must be freed.
|
||||
*/
|
||||
uint8_t *read_rom_to_ram(const char *file_name) {
|
||||
FILE *rom_file = fopen(file_name, "rb");
|
||||
size_t rom_size;
|
||||
uint8_t *rom = NULL;
|
||||
|
||||
if (rom_file == NULL)
|
||||
return NULL;
|
||||
|
||||
fseek(rom_file, 0, SEEK_END);
|
||||
rom_size = ftell(rom_file);
|
||||
rewind(rom_file);
|
||||
rom = malloc(rom_size);
|
||||
|
||||
if (fread(rom, sizeof(uint8_t), rom_size, rom_file) != rom_size) {
|
||||
free(rom);
|
||||
fclose(rom_file);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fclose(rom_file);
|
||||
return rom;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ignore all errors.
|
||||
*/
|
||||
void gb_error(struct gb_s *gb, const enum gb_error_e gb_err,
|
||||
const uint16_t val) {
|
||||
const char *gb_err_str[GB_INVALID_MAX] = {"UNKNOWN", "INVALID OPCODE",
|
||||
"INVALID READ", "INVALID WRITE",
|
||||
"HALT FOREVER"};
|
||||
struct priv_t *priv = gb->direct.priv;
|
||||
|
||||
fprintf(stderr, "Error %d occurred: %s at %04X\n. Exiting.\n", gb_err,
|
||||
gb_err_str[gb_err], val);
|
||||
|
||||
/* Free memory and then exit. */
|
||||
free(priv->cart_ram);
|
||||
free(priv->rom);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
#if ENABLE_LCD
|
||||
/**
|
||||
* Draws scanline into framebuffer.
|
||||
*/
|
||||
void lcd_draw_line(struct gb_s *gb, const uint8_t pixels[160],
|
||||
const uint_fast8_t line) {
|
||||
struct priv_t *priv = gb->direct.priv;
|
||||
const MwU8 palette[] = {0xFF, 0xA5, 0x52, 0x00};
|
||||
|
||||
for (unsigned int x = 0; x < LCD_WIDTH; x++) {
|
||||
MwU8 p = (pixels[x] & LCD_PALETTE_ALL);
|
||||
|
||||
int i = ((line * LCD_WIDTH) + x) * 4;
|
||||
priv->fb[i] = p;
|
||||
priv->fb[i + 1] = p;
|
||||
priv->fb[i + 2] = p;
|
||||
priv->fb[i + 3] = 255;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
/* Must be freed */
|
||||
char *rom_file_name = NULL;
|
||||
static struct gb_s gb;
|
||||
enum gb_init_error_e ret;
|
||||
|
||||
switch (argc) {
|
||||
case 2:
|
||||
rom_file_name = argv[1];
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(stderr, "%s ROM\n", argv[0]);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* Copy input ROM file to allocated memory. */
|
||||
if ((priv.rom = read_rom_to_ram(rom_file_name)) == NULL) {
|
||||
printf("%d: %s\n", __LINE__, strerror(errno));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* Initialise context. */
|
||||
ret = gb_init(&gb, &gb_rom_read, &gb_cart_ram_read, &gb_cart_ram_write,
|
||||
&gb_error, &priv);
|
||||
|
||||
if (ret != GB_INIT_NO_ERROR) {
|
||||
printf("Error: %d\n", ret);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
priv.cart_ram = malloc(gb_get_save_size(&gb));
|
||||
|
||||
#if ENABLE_LCD
|
||||
gb_init_lcd(&gb, &lcd_draw_line);
|
||||
// gb.direct.interlace = true;
|
||||
#endif
|
||||
|
||||
if (!mfb_open("Peanut-minifb", LCD_WIDTH, LCD_HEIGHT))
|
||||
return EXIT_FAILURE;
|
||||
|
||||
while (1) {
|
||||
const double target_speed_us = 1000000.0 / VERTICAL_SYNC;
|
||||
int_fast16_t delay;
|
||||
unsigned long start, end;
|
||||
struct timeval timecheck;
|
||||
int state;
|
||||
|
||||
gettimeofday(&timecheck, NULL);
|
||||
start = (long)timecheck.tv_sec * 1000000 + (long)timecheck.tv_usec;
|
||||
|
||||
/* Execute CPU cycles until the screen has to be redrawn. */
|
||||
gb_run_frame(&gb);
|
||||
|
||||
state = mfb_update(priv.fb);
|
||||
|
||||
/* ESC pressed */
|
||||
if (state < 0)
|
||||
break;
|
||||
|
||||
gettimeofday(&timecheck, NULL);
|
||||
end = (long)timecheck.tv_sec * 1000000 + (long)timecheck.tv_usec;
|
||||
|
||||
delay = target_speed_us - (end - start);
|
||||
|
||||
/* If it took more than the maximum allowed time to draw frame,
|
||||
* do not delay.
|
||||
* Interlaced mode could be enabled here to help speed up
|
||||
* drawing.
|
||||
*/
|
||||
if (delay < 0)
|
||||
continue;
|
||||
|
||||
usleep(delay);
|
||||
}
|
||||
|
||||
mfb_close();
|
||||
free(priv.cart_ram);
|
||||
free(priv.rom);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
3846
peanut_gb.h
Normal file
3846
peanut_gb.h
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue