Full savestating to memory
This commit is contained in:
@ -135,6 +135,13 @@ typedef struct {
|
|||||||
|
|
||||||
} audio_context;
|
} audio_context;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
audio_context ctx;
|
||||||
|
} audio_state;
|
||||||
|
|
||||||
|
void audio_save_state(audio_state*);
|
||||||
|
void audio_load_state(const audio_state*);
|
||||||
|
|
||||||
void audio_init();
|
void audio_init();
|
||||||
void audio_tick();
|
void audio_tick();
|
||||||
void audio_period_tick();
|
void audio_period_tick();
|
||||||
|
@ -19,6 +19,46 @@ typedef struct {
|
|||||||
u16 global_checksum;
|
u16 global_checksum;
|
||||||
} rom_header;
|
} rom_header;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char filename[1024];
|
||||||
|
u32 rom_size;
|
||||||
|
u8 *rom_data;
|
||||||
|
rom_header *header;
|
||||||
|
|
||||||
|
//mbc1 data
|
||||||
|
bool ram_enabled;
|
||||||
|
bool ram_banking;
|
||||||
|
|
||||||
|
u8 *rom_bank_x;
|
||||||
|
u8 *rom_bank_x2;
|
||||||
|
u8 banking_mode;
|
||||||
|
|
||||||
|
u8 rom_bank_value;
|
||||||
|
u8 rom_bank_value_2;
|
||||||
|
u8 ram_bank_value;
|
||||||
|
|
||||||
|
u8 *ram_bank;
|
||||||
|
u8 *ram_banks[16];
|
||||||
|
|
||||||
|
//battery
|
||||||
|
bool battery;
|
||||||
|
bool need_save;
|
||||||
|
} cart_context;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
bool ram_enabled;
|
||||||
|
bool ram_banking;
|
||||||
|
u8 banking_mode;
|
||||||
|
u8 rom_bank_value;
|
||||||
|
u8 rom_bank_value_2;
|
||||||
|
u8 ram_bank_value;
|
||||||
|
u8 ram_banks[16][0x2000];
|
||||||
|
bool need_save;
|
||||||
|
} cart_state;
|
||||||
|
|
||||||
|
void cart_load_state(const cart_state*);
|
||||||
|
void cart_save_state(cart_state*);
|
||||||
|
|
||||||
bool cart_load(char *cart);
|
bool cart_load(char *cart);
|
||||||
|
|
||||||
rom_header *get_rom_header();
|
rom_header *get_rom_header();
|
||||||
|
@ -35,6 +35,13 @@ typedef struct {
|
|||||||
u8 int_flags;
|
u8 int_flags;
|
||||||
} cpu_context;
|
} cpu_context;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
cpu_context ctx;
|
||||||
|
} cpu_state;
|
||||||
|
|
||||||
|
void cpu_save_state(cpu_state*);
|
||||||
|
void cpu_load_state(const cpu_state*);
|
||||||
|
|
||||||
void cpu_init();
|
void cpu_init();
|
||||||
bool cpu_step();
|
bool cpu_step();
|
||||||
|
|
||||||
|
@ -2,6 +2,20 @@
|
|||||||
|
|
||||||
#include <common.h>
|
#include <common.h>
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
bool active;
|
||||||
|
u8 byte;
|
||||||
|
u8 value;
|
||||||
|
u8 start_delay;
|
||||||
|
} dma_context;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
dma_context ctx;
|
||||||
|
} dma_state;
|
||||||
|
|
||||||
|
void dma_save_state(dma_state*);
|
||||||
|
void dma_load_state(const dma_state*);
|
||||||
|
|
||||||
void dma_start(u8 start);
|
void dma_start(u8 start);
|
||||||
void dma_tick();
|
void dma_tick();
|
||||||
|
|
||||||
|
@ -15,3 +15,6 @@ int emu_run(int, char**);
|
|||||||
emu_context *emu_get_context();
|
emu_context *emu_get_context();
|
||||||
|
|
||||||
void emu_cycles(int cpu_cycles);
|
void emu_cycles(int cpu_cycles);
|
||||||
|
void emu_reset();
|
||||||
|
void emu_stop();
|
||||||
|
void emu_start();
|
@ -13,6 +13,20 @@ typedef struct {
|
|||||||
bool right;
|
bool right;
|
||||||
} gamepad_state;
|
} gamepad_state;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
bool button_sel;
|
||||||
|
bool dir_sel;
|
||||||
|
gamepad_state controller;
|
||||||
|
gamepad_state prev;
|
||||||
|
} gamepad_context;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
gamepad_context ctx;
|
||||||
|
} ctlr_state;
|
||||||
|
|
||||||
|
void gamepad_save_state(ctlr_state*);
|
||||||
|
void gamepad_load_state(const ctlr_state*);
|
||||||
|
|
||||||
void gamepad_init();
|
void gamepad_init();
|
||||||
bool gamepad_button_sel();
|
bool gamepad_button_sel();
|
||||||
bool gamepad_dir_sel();
|
bool gamepad_dir_sel();
|
||||||
|
@ -29,6 +29,13 @@ typedef enum {
|
|||||||
MODE_XFER
|
MODE_XFER
|
||||||
} lcd_mode;
|
} lcd_mode;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
lcd_context ctx;
|
||||||
|
} lcd_state;
|
||||||
|
|
||||||
|
void lcd_save_state(lcd_state*);
|
||||||
|
void lcd_load_state(const lcd_state*);
|
||||||
|
|
||||||
lcd_context *lcd_get_context();
|
lcd_context *lcd_get_context();
|
||||||
|
|
||||||
#define LCDC_BGW_ENABLE (BIT(lcd_get_context()->lcdc, 0))
|
#define LCDC_BGW_ENABLE (BIT(lcd_get_context()->lcdc, 0))
|
||||||
|
@ -86,6 +86,13 @@ typedef struct {
|
|||||||
bool debug;
|
bool debug;
|
||||||
} ppu_context;
|
} ppu_context;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
ppu_context ctx;
|
||||||
|
} ppu_state;
|
||||||
|
|
||||||
|
void ppu_save_state(ppu_state*);
|
||||||
|
void ppu_load_state(const ppu_state*);
|
||||||
|
|
||||||
void ppu_init();
|
void ppu_init();
|
||||||
void ppu_tick();
|
void ppu_tick();
|
||||||
|
|
||||||
|
@ -2,6 +2,18 @@
|
|||||||
|
|
||||||
#include <common.h>
|
#include <common.h>
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
u8 wram[0x2000];
|
||||||
|
u8 hram[0x80];
|
||||||
|
} ram_context;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
ram_context ctx;
|
||||||
|
} ram_state;
|
||||||
|
|
||||||
|
void ram_save_state(ram_state*);
|
||||||
|
void ram_load_state(const ram_state*);
|
||||||
|
|
||||||
u8 wram_read(u16 address);
|
u8 wram_read(u16 address);
|
||||||
void wram_write(u16 address, u8 value);
|
void wram_write(u16 address, u8 value);
|
||||||
|
|
||||||
|
25
include/state.h
Normal file
25
include/state.h
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <audio.h>
|
||||||
|
#include <cpu.h>
|
||||||
|
#include <ppu.h>
|
||||||
|
#include <cart.h>
|
||||||
|
#include <dma.h>
|
||||||
|
#include <gamepad.h>
|
||||||
|
#include <ram.h>
|
||||||
|
#include <timer.h>
|
||||||
|
#include <lcd.h>
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
audio_state audio;
|
||||||
|
ppu_state ppu;
|
||||||
|
cpu_state cpu;
|
||||||
|
cart_state cart;
|
||||||
|
dma_state dma;
|
||||||
|
ctlr_state ctlr;
|
||||||
|
ram_state ram;
|
||||||
|
timer_state timer;
|
||||||
|
lcd_state lcd;
|
||||||
|
} save_state;
|
||||||
|
|
||||||
|
void state_save(save_state*);
|
||||||
|
void state_load(const save_state*);
|
@ -9,6 +9,13 @@ typedef struct {
|
|||||||
u8 tac;
|
u8 tac;
|
||||||
} timer_context;
|
} timer_context;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
timer_context ctx;
|
||||||
|
} timer_state;
|
||||||
|
|
||||||
|
void timer_save_state(timer_state*);
|
||||||
|
void timer_load_state(const timer_state*);
|
||||||
|
|
||||||
void timer_init();
|
void timer_init();
|
||||||
void timer_tick();
|
void timer_tick();
|
||||||
|
|
||||||
|
12
lib/audio.c
12
lib/audio.c
@ -992,3 +992,15 @@ void audio_write(u16 address, u8 value){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void audio_save_state(audio_state* state) {
|
||||||
|
state->ctx = ctx;
|
||||||
|
state->ctx.left_audio_buffer = 0;
|
||||||
|
state->ctx.right_audio_buffer = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void audio_load_state(const audio_state* state) {
|
||||||
|
ctx = state->ctx;
|
||||||
|
ctx.left_audio_buffer = malloc(sizeof(float) * FRAMES_PER_BUFFER);
|
||||||
|
ctx.right_audio_buffer = malloc(sizeof(float) * FRAMES_PER_BUFFER);
|
||||||
|
}
|
115
lib/cart.c
115
lib/cart.c
@ -2,32 +2,6 @@
|
|||||||
#include <common.h>
|
#include <common.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
char filename[1024];
|
|
||||||
u32 rom_size;
|
|
||||||
u8 *rom_data;
|
|
||||||
rom_header *header;
|
|
||||||
|
|
||||||
//mbc1 data
|
|
||||||
bool ram_enabled;
|
|
||||||
bool ram_banking;
|
|
||||||
|
|
||||||
u8 *rom_bank_x;
|
|
||||||
u8 *rom_bank_x2;
|
|
||||||
u8 banking_mode;
|
|
||||||
|
|
||||||
u8 rom_bank_value;
|
|
||||||
u8 rom_bank_value_2;
|
|
||||||
u8 ram_bank_value;
|
|
||||||
|
|
||||||
u8 *ram_bank;
|
|
||||||
u8 *ram_banks[16];
|
|
||||||
|
|
||||||
//battery
|
|
||||||
bool battery;
|
|
||||||
bool need_save;
|
|
||||||
} cart_context;
|
|
||||||
|
|
||||||
static cart_context ctx;
|
static cart_context ctx;
|
||||||
|
|
||||||
bool cart_need_save () {
|
bool cart_need_save () {
|
||||||
@ -174,7 +148,7 @@ const char *cart_lic_name() {
|
|||||||
|
|
||||||
void cart_setup_bamking() {
|
void cart_setup_bamking() {
|
||||||
for (int i=0; i<16; i++) {
|
for (int i=0; i<16; i++) {
|
||||||
ctx.ram_banks[1] = 0;
|
ctx.ram_banks[i] = 0;
|
||||||
|
|
||||||
if((ctx.header->ram_size == 2 && i == 0) ||
|
if((ctx.header->ram_size == 2 && i == 0) ||
|
||||||
(ctx.header->ram_size == 3 && i < 4) ||
|
(ctx.header->ram_size == 3 && i < 4) ||
|
||||||
@ -190,6 +164,46 @@ void cart_setup_bamking() {
|
|||||||
ctx.rom_bank_x2 = ctx.rom_data;
|
ctx.rom_bank_x2 = ctx.rom_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool cart_init() {
|
||||||
|
char filename[1024];
|
||||||
|
u32 rom_size;
|
||||||
|
u8 *rom_data;
|
||||||
|
rom_header *header;
|
||||||
|
|
||||||
|
//mbc1 data
|
||||||
|
bool ram_enabled;
|
||||||
|
bool ram_banking;
|
||||||
|
|
||||||
|
u8 *rom_bank_x;
|
||||||
|
u8 *rom_bank_x2;
|
||||||
|
u8 banking_mode;
|
||||||
|
|
||||||
|
u8 rom_bank_value;
|
||||||
|
u8 rom_bank_value_2;
|
||||||
|
u8 ram_bank_value;
|
||||||
|
|
||||||
|
u8 *ram_bank;
|
||||||
|
u8 *ram_banks[16];
|
||||||
|
|
||||||
|
//battery
|
||||||
|
bool battery;
|
||||||
|
bool need_save;
|
||||||
|
|
||||||
|
ctx.ram_enabled = 0;
|
||||||
|
ctx.ram_banking = 0;
|
||||||
|
ctx.rom_bank_x = ctx.rom_data;
|
||||||
|
ctx.rom_bank_x2 = ctx.rom_data;
|
||||||
|
ctx.banking_mode = 0;
|
||||||
|
ctx.rom_bank_value = 1;
|
||||||
|
ctx.rom_bank_value_2 = 0;
|
||||||
|
ctx.ram_bank_value = 0;
|
||||||
|
cart_setup_bamking();
|
||||||
|
ctx.need_save = 0;
|
||||||
|
if(ctx.battery) {
|
||||||
|
cart_battery_load();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool cart_load(char *cart) {
|
bool cart_load(char *cart) {
|
||||||
snprintf(ctx.filename, sizeof(ctx.filename), "%s", cart);
|
snprintf(ctx.filename, sizeof(ctx.filename), "%s", cart);
|
||||||
FILE *fp = fopen(cart, "r");
|
FILE *fp = fopen(cart, "r");
|
||||||
@ -388,3 +402,50 @@ bool cart_battery_save(){
|
|||||||
u8 cart_get_rom_bank() {
|
u8 cart_get_rom_bank() {
|
||||||
return ctx.rom_bank_value;
|
return ctx.rom_bank_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void cart_load_state(const cart_state* state){
|
||||||
|
ctx.ram_enabled = state->ram_enabled;
|
||||||
|
ctx.ram_banking = state->ram_banking;
|
||||||
|
ctx.banking_mode = state->banking_mode;
|
||||||
|
ctx.rom_bank_value = state->rom_bank_value;
|
||||||
|
ctx.rom_bank_value_2 = state->rom_bank_value_2;
|
||||||
|
ctx.ram_bank_value = state->ram_bank_value;
|
||||||
|
ctx.need_save = state->need_save;
|
||||||
|
|
||||||
|
for(int i = 0; i < 16; i++) {
|
||||||
|
if(ctx.ram_banks[i]){
|
||||||
|
memcpy(ctx.ram_banks[i], &state->ram_banks[i], 0x2000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ctx.banking_mode) {
|
||||||
|
ctx.rom_bank_x = ctx.rom_data + (0x4000 * (ctx.rom_bank_value+ctx.rom_bank_value_2));
|
||||||
|
ctx.rom_bank_x2 = ctx.rom_data + (0x4000 * (ctx.rom_bank_value_2));
|
||||||
|
} else {
|
||||||
|
ctx.rom_bank_x = ctx.rom_data + (0x4000 * (ctx.rom_bank_value));
|
||||||
|
ctx.rom_bank_x2 = ctx.rom_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ctx.ram_banking) {
|
||||||
|
ctx.ram_bank = ctx.ram_banks[ctx.ram_bank_value];
|
||||||
|
} else {
|
||||||
|
ctx.ram_bank = ctx.ram_banks[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void cart_save_state(cart_state* state){
|
||||||
|
state->ram_enabled = ctx.ram_enabled;
|
||||||
|
state->ram_banking = ctx.ram_banking;
|
||||||
|
state->banking_mode = ctx.banking_mode;
|
||||||
|
state->rom_bank_value = ctx.rom_bank_value;
|
||||||
|
state->rom_bank_value_2 = ctx.rom_bank_value_2;
|
||||||
|
state->ram_bank_value = ctx.ram_bank_value;
|
||||||
|
state->need_save = ctx.need_save;
|
||||||
|
|
||||||
|
for (int i=0; i<16; i++) {
|
||||||
|
if(ctx.ram_banks[i]) {
|
||||||
|
memcpy((&state->ram_banks[i]), ctx.ram_banks[i], 0x2000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -5,6 +5,7 @@
|
|||||||
#include <interrupts.h>
|
#include <interrupts.h>
|
||||||
#include <dbg.h>
|
#include <dbg.h>
|
||||||
#include <timer.h>
|
#include <timer.h>
|
||||||
|
#include <memory.h>
|
||||||
|
|
||||||
cpu_context ctx = {0};
|
cpu_context ctx = {0};
|
||||||
#define CPU_DEBUG 0
|
#define CPU_DEBUG 0
|
||||||
@ -124,3 +125,11 @@ void cpu_request_interrupt(interrupt_type t) {
|
|||||||
cpu_context *cpu_get_context() {
|
cpu_context *cpu_get_context() {
|
||||||
return &ctx;
|
return &ctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void cpu_save_state(cpu_state* state) {
|
||||||
|
state->ctx = ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cpu_load_state(const cpu_state* state) {
|
||||||
|
ctx = state->ctx;
|
||||||
|
}
|
15
lib/dma.c
15
lib/dma.c
@ -2,13 +2,6 @@
|
|||||||
#include <ppu.h>
|
#include <ppu.h>
|
||||||
#include <bus.h>
|
#include <bus.h>
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
bool active;
|
|
||||||
u8 byte;
|
|
||||||
u8 value;
|
|
||||||
u8 start_delay;
|
|
||||||
} dma_context;
|
|
||||||
|
|
||||||
static dma_context ctx;
|
static dma_context ctx;
|
||||||
|
|
||||||
void dma_start(u8 start) {
|
void dma_start(u8 start) {
|
||||||
@ -38,3 +31,11 @@ void dma_tick() {
|
|||||||
bool dma_transferring() {
|
bool dma_transferring() {
|
||||||
return ctx.active;
|
return ctx.active;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void dma_save_state(dma_state* state) {
|
||||||
|
state->ctx = ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dma_load_state(const dma_state* state) {
|
||||||
|
ctx = state->ctx;
|
||||||
|
}
|
33
lib/emu.c
33
lib/emu.c
@ -7,6 +7,7 @@
|
|||||||
#include <dma.h>
|
#include <dma.h>
|
||||||
#include <ppu.h>
|
#include <ppu.h>
|
||||||
#include <audio.h>
|
#include <audio.h>
|
||||||
|
#include <cart.h>
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
@ -16,6 +17,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
static emu_context ctx;
|
static emu_context ctx;
|
||||||
|
static HANDLE thread;
|
||||||
|
|
||||||
emu_context *emu_get_context() {
|
emu_context *emu_get_context() {
|
||||||
return &ctx;
|
return &ctx;
|
||||||
@ -26,10 +28,6 @@ DWORD WINAPI cpu_run(void *p) {
|
|||||||
#else
|
#else
|
||||||
void *cpu_run(void *p) {
|
void *cpu_run(void *p) {
|
||||||
#endif
|
#endif
|
||||||
ppu_init();
|
|
||||||
timer_init();
|
|
||||||
cpu_init();
|
|
||||||
audio_init();
|
|
||||||
|
|
||||||
ctx.running = true;
|
ctx.running = true;
|
||||||
ctx.paused = false;
|
ctx.paused = false;
|
||||||
@ -59,6 +57,26 @@ void sleep_ms(int milis) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void emu_stop() {
|
||||||
|
ctx.running = false;
|
||||||
|
WaitForSingleObject(thread, INFINITE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void emu_reset() {
|
||||||
|
ppu_init();
|
||||||
|
timer_init();
|
||||||
|
cpu_init();
|
||||||
|
audio_init();
|
||||||
|
cart_init();
|
||||||
|
}
|
||||||
|
|
||||||
|
void emu_start() {
|
||||||
|
thread = CreateThread(NULL, 0, cpu_run, NULL, 0, NULL);
|
||||||
|
if(!thread) {
|
||||||
|
fprintf(stderr, "Unable to create main CPU thread!\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int emu_run(int argc, char **argv) {
|
int emu_run(int argc, char **argv) {
|
||||||
if (argc < 2) {
|
if (argc < 2) {
|
||||||
printf("Usage: gbemu <rom_file>\n");
|
printf("Usage: gbemu <rom_file>\n");
|
||||||
@ -75,11 +93,8 @@ int emu_run(int argc, char **argv) {
|
|||||||
|
|
||||||
ui_init();
|
ui_init();
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
HANDLE thread = CreateThread(NULL, 0, cpu_run, NULL, 0, NULL);
|
emu_reset();
|
||||||
if(!thread) {
|
emu_start();
|
||||||
fprintf(stderr, "Unable to create main CPU thread!\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
#else
|
#else
|
||||||
pthread_t t1;
|
pthread_t t1;
|
||||||
if(pthread_create(&t1, NULL, cpu_run, NULL)) {
|
if(pthread_create(&t1, NULL, cpu_run, NULL)) {
|
||||||
|
@ -2,13 +2,6 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <interrupts.h>
|
#include <interrupts.h>
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
bool button_sel;
|
|
||||||
bool dir_sel;
|
|
||||||
gamepad_state controller;
|
|
||||||
gamepad_state prev;
|
|
||||||
} gamepad_context;
|
|
||||||
|
|
||||||
static gamepad_context ctx = {0};
|
static gamepad_context ctx = {0};
|
||||||
|
|
||||||
void gamepad_init();
|
void gamepad_init();
|
||||||
@ -80,3 +73,11 @@ u8 gamepad_get_output() {
|
|||||||
|
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void gamepad_save_state(ctlr_state* state){
|
||||||
|
state->ctx = ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
void gamepad_load_state(const ctlr_state* state){
|
||||||
|
ctx = state->ctx;
|
||||||
|
}
|
@ -79,3 +79,11 @@ void lcd_write(u16 address, u8 value) {
|
|||||||
update_palette(value & 0b11111100, 2);
|
update_palette(value & 0b11111100, 2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void lcd_save_state(lcd_state* state){
|
||||||
|
state->ctx = ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
void lcd_load_state(const lcd_state* state) {
|
||||||
|
ctx = state->ctx;
|
||||||
|
}
|
15
lib/ppu.c
15
lib/ppu.c
@ -85,3 +85,18 @@ void ppu_vram_write(u16 address, u8 value){
|
|||||||
u8 ppu_vram_read(u16 address){
|
u8 ppu_vram_read(u16 address){
|
||||||
return ctx.vram[address - 0x8000];
|
return ctx.vram[address - 0x8000];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ppu_save_state(ppu_state* state) {
|
||||||
|
state->ctx = ctx;
|
||||||
|
state->ctx.line_sprites = NULL;
|
||||||
|
state->ctx.line_sprite_count = 0;
|
||||||
|
state->ctx.pfc.pixel_fifo.size = 0;
|
||||||
|
state->ctx.pfc.pixel_fifo.head = 0;
|
||||||
|
state->ctx.pfc.pixel_fifo.tail = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ppu_load_state(const ppu_state* state) {
|
||||||
|
free(ctx.video_buffer);
|
||||||
|
ctx = state->ctx;
|
||||||
|
ctx.video_buffer = malloc(YRES * XRES * sizeof(u32));
|
||||||
|
}
|
13
lib/ram.c
13
lib/ram.c
@ -1,10 +1,5 @@
|
|||||||
#include <ram.h>
|
#include <ram.h>
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
u8 wram[0x2000];
|
|
||||||
u8 hram[0x80];
|
|
||||||
} ram_context;
|
|
||||||
|
|
||||||
static ram_context ctx;
|
static ram_context ctx;
|
||||||
|
|
||||||
u8 wram_read(u16 address) {
|
u8 wram_read(u16 address) {
|
||||||
@ -28,3 +23,11 @@ void hram_write(u16 address, u8 value){
|
|||||||
address -= 0xFF80;
|
address -= 0xFF80;
|
||||||
ctx.hram[address] = value;
|
ctx.hram[address] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ram_save_state(ram_state* state) {
|
||||||
|
state->ctx = ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ram_load_state(const ram_state* state) {
|
||||||
|
ctx = state->ctx;
|
||||||
|
}
|
27
lib/state.c
Normal file
27
lib/state.c
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
#include <state.h>
|
||||||
|
|
||||||
|
void state_save(save_state* state) {
|
||||||
|
printf("Saving state\n");
|
||||||
|
cpu_save_state(&state->cpu);
|
||||||
|
ram_save_state(&state->ram);
|
||||||
|
ppu_save_state(&state->ppu);
|
||||||
|
lcd_save_state(&state->lcd);
|
||||||
|
dma_save_state(&state->dma);
|
||||||
|
timer_save_state(&state->timer);
|
||||||
|
audio_save_state(&state->audio);
|
||||||
|
gamepad_save_state(&state->ctlr);
|
||||||
|
cart_save_state(&state->cart);
|
||||||
|
}
|
||||||
|
|
||||||
|
void state_load(const save_state* state) {
|
||||||
|
printf("Loading state\n");
|
||||||
|
cpu_load_state(&state->cpu);
|
||||||
|
ram_load_state(&state->ram);
|
||||||
|
ppu_load_state(&state->ppu);
|
||||||
|
lcd_load_state(&state->lcd);
|
||||||
|
dma_load_state(&state->dma);
|
||||||
|
timer_load_state(&state->timer);
|
||||||
|
audio_load_state(&state->audio);
|
||||||
|
gamepad_load_state(&state->ctlr);
|
||||||
|
cart_load_state(&state->cart);
|
||||||
|
}
|
@ -97,3 +97,11 @@ u8 timer_read(u16 address) {
|
|||||||
timer_context *timer_get_context() {
|
timer_context *timer_get_context() {
|
||||||
return &ctx;
|
return &ctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void timer_save_state(timer_state* state) {
|
||||||
|
state->ctx = ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
void timer_load_state(const timer_state* state) {
|
||||||
|
ctx = state->ctx;
|
||||||
|
}
|
19
lib/ui.c
19
lib/ui.c
@ -8,6 +8,7 @@
|
|||||||
#include <lcd.h>
|
#include <lcd.h>
|
||||||
#include <cpu.h>
|
#include <cpu.h>
|
||||||
#include <cart.h>
|
#include <cart.h>
|
||||||
|
#include <state.h>
|
||||||
|
|
||||||
#include <SDL.h>
|
#include <SDL.h>
|
||||||
#include <SDL_ttf.h>
|
#include <SDL_ttf.h>
|
||||||
@ -24,10 +25,12 @@ SDL_Renderer *sdlDebugRenderer;
|
|||||||
SDL_Texture *sdlDebugTexture;
|
SDL_Texture *sdlDebugTexture;
|
||||||
SDL_Surface *debugScreen;
|
SDL_Surface *debugScreen;
|
||||||
TTF_Font *sans;
|
TTF_Font *sans;
|
||||||
|
save_state *state;
|
||||||
|
|
||||||
static int scale = 4;
|
static int scale = 4;
|
||||||
|
|
||||||
void ui_init(){
|
void ui_init(){
|
||||||
|
state = malloc(sizeof(*state));
|
||||||
SDL_Init(SDL_INIT_VIDEO);
|
SDL_Init(SDL_INIT_VIDEO);
|
||||||
printf("SDL INIT\n");
|
printf("SDL INIT\n");
|
||||||
TTF_Init();
|
TTF_Init();
|
||||||
@ -334,6 +337,22 @@ void ui_on_key(bool down, u32 key_code) {
|
|||||||
printf("PPU Debug Disabled\n");
|
printf("PPU Debug Disabled\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if(key_code == SDLK_r && down == true) {
|
||||||
|
emu_stop();
|
||||||
|
emu_reset();
|
||||||
|
emu_start();
|
||||||
|
}
|
||||||
|
if(key_code == SDLK_s && down == true) {
|
||||||
|
emu_stop();
|
||||||
|
state_save(state);
|
||||||
|
emu_start();
|
||||||
|
}
|
||||||
|
if(key_code == SDLK_l && down == true) {
|
||||||
|
emu_stop();
|
||||||
|
emu_reset();
|
||||||
|
state_load(state);
|
||||||
|
emu_start();
|
||||||
|
}
|
||||||
switch(key_code){
|
switch(key_code){
|
||||||
case SDLK_z: gamepad_get_state()->b = down; break;
|
case SDLK_z: gamepad_get_state()->b = down; break;
|
||||||
case SDLK_x: gamepad_get_state()->a = down; break;
|
case SDLK_x: gamepad_get_state()->a = down; break;
|
||||||
|
Reference in New Issue
Block a user