Skip to content
This repository has been archived by the owner on Mar 24, 2024. It is now read-only.

Commit

Permalink
linux: Add basic gb integration
Browse files Browse the repository at this point in the history
  • Loading branch information
kbeckmann committed Jan 9, 2021
1 parent 72159e5 commit efa8e37
Show file tree
Hide file tree
Showing 7 changed files with 404 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ Core/Src/retro-go/gb_roms.c
Core/Src/retro-go/sms_roms.c
Core/Src/retro-go/gg_roms.c

linux/loaded_gb_rom.c
linux/loaded_nes_rom.c

save_states
81 changes: 81 additions & 0 deletions linux/Makefile.gb
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
TARGET = retro-go-gb

DEBUG = 1
#OPT = -Og -ggdb
OPT = -O0 -ggdb3 -fsanitize=address

BUILD_DIR = build


C_SOURCES = \
gb/main.c \
odroid_input.c \
odroid_netplay.c \
odroid_overlay.c \
odroid_sdcard.c \
odroid_system.c \
odroid_display.c \
odroid_audio.c \
gw_lcd.c \
loaded_gb_rom.c \
crc32.c \
porting.c \
../retro-go-stm32/gnuboy-go/components/gnuboy/cpu.c \
../retro-go-stm32/gnuboy-go/components/gnuboy/debug.c \
../retro-go-stm32/gnuboy-go/components/gnuboy/emu.c \
../retro-go-stm32/gnuboy-go/components/gnuboy/hw.c \
../retro-go-stm32/gnuboy-go/components/gnuboy/lcd.c \
../retro-go-stm32/gnuboy-go/components/gnuboy/loader.c \
../retro-go-stm32/gnuboy-go/components/gnuboy/mem.c \
../retro-go-stm32/gnuboy-go/components/gnuboy/rtc.c \
../retro-go-stm32/gnuboy-go/components/gnuboy/sound.c \


PREFIX =

CC = $(PREFIX)gcc
AS = $(PREFIX)gcc -x assembler-with-cpp
CP = $(PREFIX)objcopy
SZ = $(PREFIX)size

HEX = $(CP) -O ihex
BIN = $(CP) -O binary -S

C_DEFS = \
-DIS_LITTLE_ENDIAN

C_INCLUDES = \
-I. \
-I./gb \
-I../retro-go-stm32/gnuboy-go/components \
-I../retro-go-stm32/components/odroid


ASFLAGS = $(AS_DEFS) $(AS_INCLUDES) $(OPT) -Wall -fdata-sections -ffunction-sections
CFLAGS = $(C_DEFS) $(C_INCLUDES) `sdl2-config --cflags` $(OPT) -Wall -fdata-sections -ffunction-sections
CFLAGS += -MMD -MP -MF"$(@:%.o=%.d)"

#LIBS = -lm `sdl2-config --libs`
LIBS = -lasan -lm `sdl2-config --libs`
LDFLAGS = $(LIBS) -Wl,-Map=$(BUILD_DIR)/$(TARGET).map,--cref -Wl,--gc-sections

all: $(BUILD_DIR)/$(TARGET).elf

OBJECTS = $(addprefix $(BUILD_DIR)/,$(notdir $(C_SOURCES:.c=.o)))
vpath %.c $(sort $(dir $(C_SOURCES)))


$(BUILD_DIR)/%.o: %.c Makefile.gb | $(BUILD_DIR)
$(CC) -c $(CFLAGS) -Wa,-a,-ad,-alms=$(BUILD_DIR)/$(notdir $(<:.c=.lst)) $< -o $@

$(BUILD_DIR)/$(TARGET).elf: $(OBJECTS) Makefile.gb
$(CC) $(OBJECTS) $(LDFLAGS) -o $@
$(SZ) $@

$(BUILD_DIR):
mkdir $@

clean:
-rm -fR $(BUILD_DIR)

-include $(wildcard $(BUILD_DIR)/*.d)
222 changes: 222 additions & 0 deletions linux/gb/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,222 @@
#include <odroid_system.h>

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>

#include <SDL2/SDL.h>

#include <odroid_system.h>

#include "porting.h"
#include "crc32.h"

#include "gw_lcd.h"
#include "gnuboy/loader.h"
#include "gnuboy/hw.h"
#include "gnuboy/lcd.h"
#include "gnuboy/cpu.h"
#include "gnuboy/mem.h"
#include "gnuboy/sound.h"
#include "gnuboy/regs.h"
#include "gnuboy/rtc.h"
#include "gnuboy/defs.h"

#define APP_ID 20

#define NVS_KEY_SAVE_SRAM "sram"

#define WIDTH GB_WIDTH
#define HEIGHT GB_HEIGHT
#define BPP 2
#define SCALE 4

#define AUDIO_SAMPLE_RATE (48000)
#define AUDIO_BUFFER_LENGTH (AUDIO_SAMPLE_RATE / 60)

// Use 60Hz for GB
#define AUDIO_BUFFER_LENGTH_GB (AUDIO_SAMPLE_RATE / 60)
#define AUDIO_BUFFER_LENGTH_DMA_GB ((2 * AUDIO_SAMPLE_RATE) / 60)

static odroid_video_frame_t update1 = {GB_WIDTH, GB_HEIGHT, GB_WIDTH * 2, 2, 0xFF, -1, NULL, NULL, 0, {}};
static odroid_video_frame_t update2 = {GB_WIDTH, GB_HEIGHT, GB_WIDTH * 2, 2, 0xFF, -1, NULL, NULL, 0, {}};
static odroid_video_frame_t *currentUpdate = &update1;

static bool fullFrame = false;
static uint skipFrames = 0;

static bool saveSRAM = false;

// 3 pages
uint8_t state_save_buffer[192 * 1024];

SDL_Window *window;
SDL_Renderer *renderer;
SDL_Texture *fb_texture;
uint16_t fb_data[WIDTH * HEIGHT * BPP];

SDL_AudioSpec wanted;
void fill_audio(void *udata, Uint8 *stream, int len);

extern unsigned char cart_rom[];
extern unsigned int cart_rom_len;

void odroid_display_force_refresh(void)
{
// forceVideoRefresh = true;
}


static inline void blit(void) {
// we want 60 Hz for NTSC
int wantedTime = 1000 / 60;
SDL_Delay(wantedTime); // rendering takes basically "0ms"

memcpy(fb_data, currentUpdate->buffer, sizeof(fb_data));

SDL_UpdateTexture(fb_texture, NULL, fb_data, WIDTH * BPP);
SDL_RenderCopy(renderer, fb_texture, NULL, NULL);
SDL_RenderPresent(renderer);
}

void fill_audio(void *udata, Uint8 *stream, int len)
{

}

int init_window(int width, int height)
{
if (SDL_Init(SDL_INIT_VIDEO) != 0)
return 0;

window = SDL_CreateWindow("emulator",
SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
width * SCALE, height * SCALE,
0);
if (!window)
return 0;

renderer = SDL_CreateRenderer(window, -1,
SDL_RENDERER_PRESENTVSYNC);
if (!renderer)
return 0;

fb_texture = SDL_CreateTexture(renderer,
SDL_PIXELFORMAT_RGB565, SDL_TEXTUREACCESS_STREAMING,
width, height);
if (!fb_texture)
return 0;


#if 0
/* Set the audio format */
wanted.freq = AUDIO_SAMPLE_RATE;
wanted.format = AUDIO_S16;
wanted.channels = 1; /* 1 = mono, 2 = stereo */
wanted.samples = AUDIO_BUFFER_LENGTH * 2; /* Good low-latency value for callback */
wanted.callback = fill_audio;
wanted.userdata = NULL;

/* Open the audio device, forcing the desired format */
if (SDL_OpenAudio(&wanted, NULL) < 0) {
fprintf(stderr, "Couldn't open audio: %s\n", SDL_GetError());
return(-1);
}

SDL_PauseAudio(0);
#endif

return 0;
}

static void netplay_callback(netplay_event_t event, void *arg)
{
// Where we're going we don't need netplay!
}

static bool SaveState(char *pathName)
{
return 0;
}

static bool LoadState(char *pathName)
{
return true;
}

void pcm_submit(void)
{

}

void init(void)
{
odroid_system_init(APP_ID, AUDIO_SAMPLE_RATE);
odroid_system_emu_init(&LoadState, &SaveState, &netplay_callback);

// Hack: Use the same buffer twice
update1.buffer = fb_data;
update2.buffer = fb_data;

//saveSRAM = odroid_settings_app_int32_get(NVS_KEY_SAVE_SRAM, 0);
saveSRAM = false;

// Load ROM
loader_init(NULL);

// RTC
memset(&rtc, 0, sizeof(rtc));

// Video
memset(fb_data, 0, sizeof(fb_data));
memset(&fb, 0, sizeof(fb));
fb.w = GB_WIDTH;
fb.h = GB_HEIGHT;
fb.pixelsize = 2;
fb.pitch = fb.w * fb.pixelsize;
fb.ptr = currentUpdate->buffer;
fb.enabled = 1;
fb.byteorder = 0;
fb.blit_func = &blit;

emu_init();

//pal_set_dmg(odroid_settings_Palette_get());
pal_set_dmg(2);
}


int main(int argc, char *argv[])
{
init_window(WIDTH, HEIGHT);

init();
odroid_gamepad_state_t joystick;

while (true)
{
odroid_input_read_gamepad(&joystick);

uint startTime = get_elapsed_time();
bool drawFrame = !skipFrames;

pad_set(PAD_UP, joystick.values[ODROID_INPUT_UP]);
pad_set(PAD_RIGHT, joystick.values[ODROID_INPUT_RIGHT]);
pad_set(PAD_DOWN, joystick.values[ODROID_INPUT_DOWN]);
pad_set(PAD_LEFT, joystick.values[ODROID_INPUT_LEFT]);
pad_set(PAD_SELECT, joystick.values[ODROID_INPUT_SELECT]);
pad_set(PAD_START, joystick.values[ODROID_INPUT_START]);
pad_set(PAD_A, joystick.values[ODROID_INPUT_A]);
pad_set(PAD_B, joystick.values[ODROID_INPUT_B]);

emu_run(drawFrame);

// Tick before submitting audio/syncing
odroid_system_tick(!drawFrame, fullFrame, get_elapsed_time_since(startTime));
}

SDL_Quit();

return 0;
}
Empty file added linux/gb/main.h
Empty file.
3 changes: 3 additions & 0 deletions linux/gb/rom_manager.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#pragma once

extern const unsigned char ROM_DATA[];
70 changes: 70 additions & 0 deletions linux/odroid_input.c
Original file line number Diff line number Diff line change
@@ -1,8 +1,78 @@
#include "odroid_system.h"
#include "odroid_input.h"

#include <SDL2/SDL.h>
static odroid_gamepad_state_t out_state;

void odroid_input_read_gamepad(odroid_gamepad_state_t* out_state)
{
SDL_Event event;
if (SDL_PollEvent(&event)) {
if (event.type == SDL_KEYDOWN) {
// printf("Press %d\n", event.key.keysym.sym);
switch (event.key.keysym.sym) {
case SDLK_x:
out_state->values[ODROID_INPUT_A] = 1;
break;
case SDLK_z:
out_state->values[ODROID_INPUT_B] = 1;
break;
case SDLK_LSHIFT:
out_state->values[ODROID_INPUT_START] = 1;
break;
case SDLK_LCTRL:
out_state->values[ODROID_INPUT_SELECT] = 1;
break;
case SDLK_UP:
out_state->values[ODROID_INPUT_UP] = 1;
break;
case SDLK_DOWN:
out_state->values[ODROID_INPUT_DOWN] = 1;
break;
case SDLK_LEFT:
out_state->values[ODROID_INPUT_LEFT] = 1;
break;
case SDLK_RIGHT:
out_state->values[ODROID_INPUT_RIGHT] = 1;
break;
case SDLK_ESCAPE:
exit(1);
break;
default:
break;
}
} else if (event.type == SDL_KEYUP) {
// printf("Release %d\n", event.key.keysym.sym);
switch (event.key.keysym.sym) {
case SDLK_x:
out_state->values[ODROID_INPUT_A] = 0;
break;
case SDLK_z:
out_state->values[ODROID_INPUT_B] = 0;
break;
case SDLK_LSHIFT:
out_state->values[ODROID_INPUT_START] = 0;
break;
case SDLK_LCTRL:
out_state->values[ODROID_INPUT_SELECT] = 0;
break;
case SDLK_UP:
out_state->values[ODROID_INPUT_UP] = 0;
break;
case SDLK_DOWN:
out_state->values[ODROID_INPUT_DOWN] = 0;
break;
case SDLK_LEFT:
out_state->values[ODROID_INPUT_LEFT] = 0;
break;
case SDLK_RIGHT:
out_state->values[ODROID_INPUT_RIGHT] = 0;
break;
default:
break;
}
}
}
}

void odroid_input_wait_for_key(odroid_gamepad_key_t key, bool pressed)
Expand Down
Loading

0 comments on commit efa8e37

Please sign in to comment.