Compare commits
7 Commits
AudioReimp
...
master
Author | SHA1 | Date | |
---|---|---|---|
4da737135d | |||
97bf116c89 | |||
5da4219f09 | |||
435a4c5ebe | |||
89cfdb4d65 | |||
2ab09f9b4c | |||
c8ec44fa39 |
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
@ -8,6 +8,7 @@
|
|||||||
"profileapi.h": "c",
|
"profileapi.h": "c",
|
||||||
"type_traits": "c",
|
"type_traits": "c",
|
||||||
"xtr1common": "c",
|
"xtr1common": "c",
|
||||||
"chrono": "c"
|
"chrono": "c",
|
||||||
|
"interrupts.h": "c"
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -28,4 +28,6 @@ void cart_write(u16 address, u8 value);
|
|||||||
|
|
||||||
bool cart_need_save();
|
bool cart_need_save();
|
||||||
bool cart_battery_load();
|
bool cart_battery_load();
|
||||||
bool cart_battery_save();
|
bool cart_battery_save();
|
||||||
|
|
||||||
|
u8 cart_get_rom_bank();
|
@ -47,6 +47,8 @@ IN_PROC inst_get_processor(in_type type);
|
|||||||
#define CPU_FLAG_H BIT(ctx->regs.f, 5)
|
#define CPU_FLAG_H BIT(ctx->regs.f, 5)
|
||||||
#define CPU_FLAG_C BIT(ctx->regs.f, 4)
|
#define CPU_FLAG_C BIT(ctx->regs.f, 4)
|
||||||
|
|
||||||
|
cpu_context *cpu_get_context();
|
||||||
|
|
||||||
u16 cpu_read_reg(reg_type rt);
|
u16 cpu_read_reg(reg_type rt);
|
||||||
|
|
||||||
void cpu_set_reg(reg_type rt, u16 val);
|
void cpu_set_reg(reg_type rt, u16 val);
|
||||||
|
@ -17,6 +17,7 @@ void gamepad_init();
|
|||||||
bool gamepad_button_sel();
|
bool gamepad_button_sel();
|
||||||
bool gamepad_dir_sel();
|
bool gamepad_dir_sel();
|
||||||
void gamepad_set_sel(u8 value);
|
void gamepad_set_sel(u8 value);
|
||||||
|
void gamepad_int_update();
|
||||||
|
|
||||||
gamepad_state *gamepad_get_state();
|
gamepad_state *gamepad_get_state();
|
||||||
u8 gamepad_get_output();
|
u8 gamepad_get_output();
|
@ -52,7 +52,7 @@ typedef enum {
|
|||||||
SS_LYC = (1 << 6)
|
SS_LYC = (1 << 6)
|
||||||
} stat_src;
|
} stat_src;
|
||||||
|
|
||||||
#define LCDS_STAT_INT(src) (lcd_get_context()->lcds & src)
|
#define LCDS_STAT_INT(src) ((lcd_get_context()->lcds & src) == src)
|
||||||
|
|
||||||
void lcd_init();
|
void lcd_init();
|
||||||
|
|
||||||
|
@ -40,6 +40,7 @@ typedef struct {
|
|||||||
u8 map_x;
|
u8 map_x;
|
||||||
u8 tile_y;
|
u8 tile_y;
|
||||||
u8 fifo_x;
|
u8 fifo_x;
|
||||||
|
u8 lo_scroll_x;
|
||||||
} pixel_fifo_context;
|
} pixel_fifo_context;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@ -82,6 +83,7 @@ typedef struct {
|
|||||||
u32 target_frame_time;
|
u32 target_frame_time;
|
||||||
bool paused;
|
bool paused;
|
||||||
bool frame;
|
bool frame;
|
||||||
|
bool debug;
|
||||||
} ppu_context;
|
} ppu_context;
|
||||||
|
|
||||||
void ppu_init();
|
void ppu_init();
|
||||||
|
17
lib/audio.c
17
lib/audio.c
@ -353,14 +353,21 @@ void audio_sample_tick() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(ctx.buffer_write_index == FRAMES_PER_BUFFER) {
|
if(ctx.buffer_write_index == FRAMES_PER_BUFFER) {
|
||||||
ctx.buffer_write_index = 0;
|
|
||||||
float *data[2];
|
float *data[2];
|
||||||
data[0] = ctx.left_audio_buffer;
|
data[0] = ctx.left_audio_buffer;
|
||||||
data[1] = ctx.right_audio_buffer;
|
data[1] = ctx.right_audio_buffer;
|
||||||
int err = Pa_WriteStream(stream, data, FRAMES_PER_BUFFER);
|
//long available = Pa_GetStreamWriteAvailable(stream);
|
||||||
if(err != paNoError && err != paOutputUnderflowed) {
|
//if(available > 0) {
|
||||||
fprintf(stderr, "portaudio stream error\n\tError Number: %d\n\tError Message: %s\n", err, Pa_GetErrorText(err));
|
// if(available > FRAMES_PER_BUFFER) {
|
||||||
}
|
// available = FRAMES_PER_BUFFER;
|
||||||
|
// }
|
||||||
|
// ctx.buffer_write_index -= available;
|
||||||
|
ctx.buffer_write_index = 0;
|
||||||
|
int err = Pa_WriteStream(stream, data, FRAMES_PER_BUFFER);
|
||||||
|
if(err != paNoError && err != paOutputUnderflowed) {
|
||||||
|
fprintf(stderr, "portaudio stream error\n\tError Number: %d\n\tError Message: %s\n", err, Pa_GetErrorText(err));
|
||||||
|
}
|
||||||
|
//}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -355,3 +355,7 @@ bool cart_battery_save(){
|
|||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u8 cart_get_rom_bank() {
|
||||||
|
return ctx.rom_bank_value;
|
||||||
|
}
|
@ -120,3 +120,7 @@ void cpu_set_ie_register(u8 ie){
|
|||||||
void cpu_request_interrupt(interrupt_type t) {
|
void cpu_request_interrupt(interrupt_type t) {
|
||||||
ctx.int_flags |= t;
|
ctx.int_flags |= t;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cpu_context *cpu_get_context() {
|
||||||
|
return &ctx;
|
||||||
|
}
|
@ -93,10 +93,10 @@ int emu_run(int argc, char **argv) {
|
|||||||
while(!ctx.die) {
|
while(!ctx.die) {
|
||||||
sleep_ms(1);
|
sleep_ms(1);
|
||||||
ui_handle_events();
|
ui_handle_events();
|
||||||
if (prev_frame != ppu_get_context()->current_frame) {
|
//if (prev_frame != ppu_get_context()->current_frame) {
|
||||||
ui_update();
|
ui_update();
|
||||||
}
|
//}
|
||||||
prev_frame = ppu_get_context()->current_frame;
|
//prev_frame = ppu_get_context()->current_frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,16 +1,33 @@
|
|||||||
#include <gamepad.h>
|
#include <gamepad.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <interrupts.h>
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
bool button_sel;
|
bool button_sel;
|
||||||
bool dir_sel;
|
bool dir_sel;
|
||||||
gamepad_state controller;
|
gamepad_state controller;
|
||||||
|
gamepad_state prev;
|
||||||
} gamepad_context;
|
} gamepad_context;
|
||||||
|
|
||||||
static gamepad_context ctx = {0};
|
static gamepad_context ctx = {0};
|
||||||
|
|
||||||
void gamepad_init();
|
void gamepad_init();
|
||||||
|
|
||||||
|
void gamepad_int_update(){
|
||||||
|
if(ctx.button_sel) {
|
||||||
|
if((ctx.prev.a == 1 && ctx.controller.a == 0) || (ctx.prev.b == 1 && ctx.controller.b == 0) || (ctx.prev.select == 1 && ctx.controller.select == 0) || (ctx.prev.start == 1 && ctx.controller.start == 0)) {
|
||||||
|
cpu_request_interrupt(IT_JOYPAD);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(ctx.dir_sel) {
|
||||||
|
if((ctx.prev.up == 1 && ctx.controller.up == 0) || (ctx.prev.down == 1 && ctx.controller.down == 0) || (ctx.prev.left == 1 && ctx.controller.left == 0) || (ctx.prev.right == 1 && ctx.controller.right == 0)) {
|
||||||
|
cpu_request_interrupt(IT_JOYPAD);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
bool gamepad_button_sel(){
|
bool gamepad_button_sel(){
|
||||||
return ctx.button_sel;
|
return ctx.button_sel;
|
||||||
}
|
}
|
||||||
|
@ -58,6 +58,14 @@ void lcd_write(u16 address, u8 value) {
|
|||||||
u8 *p = (u8 *)&ctx;
|
u8 *p = (u8 *)&ctx;
|
||||||
p[offset] = value;
|
p[offset] = value;
|
||||||
|
|
||||||
|
if(offset == 2) {
|
||||||
|
//printf("YScroll: %02X\n", value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(offset == 0xA) {
|
||||||
|
//printf("WinY: %02X\n", value);
|
||||||
|
}
|
||||||
|
|
||||||
if(offset == 6) {
|
if(offset == 6) {
|
||||||
//offset FF64
|
//offset FF64
|
||||||
dma_start(value);
|
dma_start(value);
|
||||||
|
31
lib/ppu.c
31
lib/ppu.c
@ -35,25 +35,28 @@ void ppu_init() {
|
|||||||
LCDS_MODE_SET(MODE_OAM);
|
LCDS_MODE_SET(MODE_OAM);
|
||||||
|
|
||||||
memset(ctx.oam_ram, 0, sizeof(ctx.oam_ram));
|
memset(ctx.oam_ram, 0, sizeof(ctx.oam_ram));
|
||||||
|
memset(ctx.vram, 0, sizeof(ctx.vram));
|
||||||
memset(ctx.video_buffer, 0, YRES*XRES*sizeof(u32));
|
memset(ctx.video_buffer, 0, YRES*XRES*sizeof(u32));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ppu_tick() {
|
void ppu_tick() {
|
||||||
ctx.line_ticks++;
|
if(LCDC_LCD_ENABLE){
|
||||||
|
ctx.line_ticks++;
|
||||||
|
|
||||||
switch(LCDS_MODE) {
|
switch(LCDS_MODE) {
|
||||||
case MODE_OAM:
|
case MODE_OAM:
|
||||||
ppu_mode_oam();
|
ppu_mode_oam();
|
||||||
break;
|
break;
|
||||||
case MODE_XFER:
|
case MODE_XFER:
|
||||||
ppu_mode_xfer();
|
ppu_mode_xfer();
|
||||||
break;
|
break;
|
||||||
case MODE_VBLANK:
|
case MODE_VBLANK:
|
||||||
ppu_mode_vblank();
|
ppu_mode_vblank();
|
||||||
break;
|
break;
|
||||||
case MODE_HBLANK:
|
case MODE_HBLANK:
|
||||||
ppu_mode_hblank();
|
ppu_mode_hblank();
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,7 +41,10 @@ u32 pixel_fifo_pop() {
|
|||||||
u32 fetch_sprite_pixels(int bit, u32 color, u8 bg_color) {
|
u32 fetch_sprite_pixels(int bit, u32 color, u8 bg_color) {
|
||||||
for (int i = 0; i < ppu_get_context()->fetched_entry_count; i++) {
|
for (int i = 0; i < ppu_get_context()->fetched_entry_count; i++) {
|
||||||
int sp_x = (ppu_get_context()->fetched_entries[i].x - 8) +
|
int sp_x = (ppu_get_context()->fetched_entries[i].x - 8) +
|
||||||
((lcd_get_context()->scroll_x % 8));
|
((ppu_get_context()->pfc.lo_scroll_x));
|
||||||
|
if(ppu_get_context()->rendering_window) {
|
||||||
|
sp_x = (ppu_get_context()->fetched_entries[i].x - 8);
|
||||||
|
}
|
||||||
|
|
||||||
if (sp_x + 8 < ppu_get_context()->pfc.fifo_x) {
|
if (sp_x + 8 < ppu_get_context()->pfc.fifo_x) {
|
||||||
//past this pixel already
|
//past this pixel already
|
||||||
@ -71,8 +74,8 @@ u32 fetch_sprite_pixels(int bit, u32 color, u8 bg_color) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(!bg_priority || bg_color == 0) {
|
if(!bg_priority || bg_color == 0) {
|
||||||
color = (ppu_get_context()->fetched_entries[i].f_pn) ?
|
color = ((ppu_get_context()->fetched_entries[i].f_pn) ?
|
||||||
lcd_get_context()->sp2_colors[hi|lo] : lcd_get_context()->sp1_colors[hi|lo];
|
lcd_get_context()->sp2_colors[hi|lo] : lcd_get_context()->sp1_colors[hi|lo]);
|
||||||
|
|
||||||
if(hi | lo) {
|
if(hi | lo) {
|
||||||
break;
|
break;
|
||||||
@ -89,7 +92,7 @@ bool pipeline_fifo_add() {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int x = ppu_get_context()->pfc.fetch_x - (8 - lcd_get_context()->scroll_x % 8);
|
int x = ppu_get_context()->pfc.fetch_x - (8 - ppu_get_context()->pfc.lo_scroll_x);
|
||||||
|
|
||||||
for (int i=0; i<8; i++) {
|
for (int i=0; i<8; i++) {
|
||||||
int bit = 7 - i;
|
int bit = 7 - i;
|
||||||
@ -101,7 +104,7 @@ bool pipeline_fifo_add() {
|
|||||||
color = lcd_get_context()->bg_colors[0];
|
color = lcd_get_context()->bg_colors[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
if(LCDC_OBJ_ENABLE) {
|
if(LCDC_OBJ_ENABLE && !ppu_get_context()->debug) {
|
||||||
color = fetch_sprite_pixels(bit, color, hi | lo);
|
color = fetch_sprite_pixels(bit, color, hi | lo);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -118,7 +121,7 @@ void pipeline_load_sprite_tile() {
|
|||||||
oam_line_entry *le = ppu_get_context()->line_sprites;
|
oam_line_entry *le = ppu_get_context()->line_sprites;
|
||||||
|
|
||||||
while(le) {
|
while(le) {
|
||||||
int sp_x = (le->entry.x - 8) + (lcd_get_context()->scroll_x % 8);
|
int sp_x = (le->entry.x - 8) + (ppu_get_context()->pfc.lo_scroll_x);
|
||||||
|
|
||||||
if ((sp_x >= ppu_get_context()->pfc.fetch_x && sp_x < ppu_get_context()->pfc.fetch_x + 8) ||
|
if ((sp_x >= ppu_get_context()->pfc.fetch_x && sp_x < ppu_get_context()->pfc.fetch_x + 8) ||
|
||||||
((sp_x + 8) >= ppu_get_context()->pfc.fetch_x && (sp_x + 8) < ppu_get_context()->pfc.fetch_x + 8)) {
|
((sp_x + 8) >= ppu_get_context()->pfc.fetch_x && (sp_x + 8) < ppu_get_context()->pfc.fetch_x + 8)) {
|
||||||
@ -204,7 +207,7 @@ void pipeline_fetch() {
|
|||||||
if(ppu_get_context()->rendering_window){
|
if(ppu_get_context()->rendering_window){
|
||||||
ppu_get_context()->pfc.bgw_fetch_data[1] = bus_read(LCDC_BGW_DATA_AREA +
|
ppu_get_context()->pfc.bgw_fetch_data[1] = bus_read(LCDC_BGW_DATA_AREA +
|
||||||
(ppu_get_context()->pfc.bgw_fetch_data[0] * 16) +
|
(ppu_get_context()->pfc.bgw_fetch_data[0] * 16) +
|
||||||
(lcd_get_context()->ly % 8) * 2);
|
(ppu_get_context()->window_line % 8) * 2);
|
||||||
} else {
|
} else {
|
||||||
ppu_get_context()->pfc.bgw_fetch_data[1] = bus_read(LCDC_BGW_DATA_AREA +
|
ppu_get_context()->pfc.bgw_fetch_data[1] = bus_read(LCDC_BGW_DATA_AREA +
|
||||||
(ppu_get_context()->pfc.bgw_fetch_data[0] * 16) +
|
(ppu_get_context()->pfc.bgw_fetch_data[0] * 16) +
|
||||||
@ -220,7 +223,7 @@ void pipeline_fetch() {
|
|||||||
if(ppu_get_context()->rendering_window){
|
if(ppu_get_context()->rendering_window){
|
||||||
ppu_get_context()->pfc.bgw_fetch_data[2] = bus_read(LCDC_BGW_DATA_AREA +
|
ppu_get_context()->pfc.bgw_fetch_data[2] = bus_read(LCDC_BGW_DATA_AREA +
|
||||||
(ppu_get_context()->pfc.bgw_fetch_data[0] * 16) + 1 +
|
(ppu_get_context()->pfc.bgw_fetch_data[0] * 16) + 1 +
|
||||||
(lcd_get_context()->ly % 8) * 2);
|
(ppu_get_context()->window_line % 8) * 2);
|
||||||
} else {
|
} else {
|
||||||
ppu_get_context()->pfc.bgw_fetch_data[2] = bus_read(LCDC_BGW_DATA_AREA +
|
ppu_get_context()->pfc.bgw_fetch_data[2] = bus_read(LCDC_BGW_DATA_AREA +
|
||||||
(ppu_get_context()->pfc.bgw_fetch_data[0] * 16) +
|
(ppu_get_context()->pfc.bgw_fetch_data[0] * 16) +
|
||||||
@ -252,27 +255,47 @@ void pipeline_fifo_reset() {
|
|||||||
ppu_get_context()->pfc.pixel_fifo.head = 0;
|
ppu_get_context()->pfc.pixel_fifo.head = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Rate at wich the screen interpolates between the old and new colors
|
||||||
|
//Used to simulate the slow response time of the GB's LCD
|
||||||
|
//A value of zero will always use the exiting screen color, while a 1 will always use the new color
|
||||||
|
//any value in between will interpolate that percentage between the two
|
||||||
|
#define INTERPOLATION_RATE 0.5
|
||||||
|
|
||||||
|
u32 interpolate(u32 first, u32 second) {
|
||||||
|
u32 final = 0;
|
||||||
|
for(int c = 0; c < 4; c++) {
|
||||||
|
u8 c1 = (first >> (c*8)) & 0xFF;
|
||||||
|
u8 c2 = (second >> (c*8)) & 0xFF;
|
||||||
|
u8 cf = (u8)(((((float)c2/(float)0xFF) - ((float)c1/(float)0xFF)) * INTERPOLATION_RATE + ((float)c1/(float)0xFF)) * 0xFF);
|
||||||
|
final |= cf << (c*8);
|
||||||
|
}
|
||||||
|
return final;
|
||||||
|
}
|
||||||
|
|
||||||
void pipeline_push_pixel() {
|
void pipeline_push_pixel() {
|
||||||
if (ppu_get_context()->pfc.pixel_fifo.size > 8) {
|
if (ppu_get_context()->pfc.pixel_fifo.size > 8) {
|
||||||
u32 pixel_data = pixel_fifo_pop();
|
u32 pixel_data = pixel_fifo_pop();
|
||||||
|
|
||||||
if(ppu_get_context()->pfc.pushed_x+7 >= lcd_get_context()->win_x && lcd_get_context()->ly >= lcd_get_context()->win_y && !ppu_get_context()->rendering_window && window_visible()) {
|
if(ppu_get_context()->pfc.line_x+7 >= lcd_get_context()->win_x && lcd_get_context()->ly >= lcd_get_context()->win_y && !ppu_get_context()->rendering_window && window_visible()) {
|
||||||
ppu_get_context()->rendering_window = true;
|
ppu_get_context()->rendering_window = true;
|
||||||
pipeline_fifo_reset();
|
pipeline_fifo_reset();
|
||||||
ppu_get_context()->pfc.cur_fetch_state = FS_TILE;
|
ppu_get_context()->pfc.cur_fetch_state = FS_TILE;
|
||||||
ppu_get_context()->pfc.fetch_x = 0;
|
ppu_get_context()->pfc.fetch_x = ppu_get_context()->pfc.line_x;
|
||||||
ppu_get_context()->pfc.fifo_x = 0;
|
ppu_get_context()->pfc.fifo_x = ppu_get_context()->pfc.line_x;
|
||||||
|
ppu_get_context()->pfc.pushed_x = ppu_get_context()->pfc.line_x;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(ppu_get_context()->rendering_window) {
|
if(ppu_get_context()->rendering_window) {
|
||||||
ppu_get_context()->video_buffer[ppu_get_context()->pfc.pushed_x +
|
ppu_get_context()->video_buffer[ppu_get_context()->pfc.pushed_x +
|
||||||
(lcd_get_context()->ly * XRES)] = pixel_data;
|
(lcd_get_context()->ly * XRES)] = interpolate(ppu_get_context()->video_buffer[ppu_get_context()->pfc.pushed_x +
|
||||||
|
(lcd_get_context()->ly * XRES)], pixel_data);
|
||||||
|
|
||||||
ppu_get_context()->pfc.pushed_x++;
|
ppu_get_context()->pfc.pushed_x++;
|
||||||
}else {
|
}else {
|
||||||
if(ppu_get_context()->pfc.line_x >= (lcd_get_context()->scroll_x % 8)) {
|
if(ppu_get_context()->pfc.line_x >= (ppu_get_context()->pfc.lo_scroll_x)) {
|
||||||
ppu_get_context()->video_buffer[ppu_get_context()->pfc.pushed_x +
|
ppu_get_context()->video_buffer[ppu_get_context()->pfc.pushed_x +
|
||||||
(lcd_get_context()->ly * XRES)] = pixel_data;
|
(lcd_get_context()->ly * XRES)] = interpolate(ppu_get_context()->video_buffer[ppu_get_context()->pfc.pushed_x +
|
||||||
|
(lcd_get_context()->ly * XRES)], pixel_data);
|
||||||
|
|
||||||
ppu_get_context()->pfc.pushed_x++;
|
ppu_get_context()->pfc.pushed_x++;
|
||||||
}
|
}
|
||||||
|
19
lib/ppu_sm.c
19
lib/ppu_sm.c
@ -17,7 +17,6 @@ void increment_ly() {
|
|||||||
|
|
||||||
if(lcd_get_context()->ly == lcd_get_context()->ly_compare) {
|
if(lcd_get_context()->ly == lcd_get_context()->ly_compare) {
|
||||||
LCDS_LYC_SET(1);
|
LCDS_LYC_SET(1);
|
||||||
|
|
||||||
if(LCDS_STAT_INT(SS_LYC)) {
|
if(LCDS_STAT_INT(SS_LYC)) {
|
||||||
cpu_request_interrupt(IT_LCD_STAT);
|
cpu_request_interrupt(IT_LCD_STAT);
|
||||||
}
|
}
|
||||||
@ -95,6 +94,7 @@ void ppu_mode_oam() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(ppu_get_context()->line_ticks == 1) {
|
if(ppu_get_context()->line_ticks == 1) {
|
||||||
|
ppu_get_context()->pfc.lo_scroll_x = lcd_get_context()->scroll_x & 0b111;
|
||||||
//read oam on the first tick only...
|
//read oam on the first tick only...
|
||||||
ppu_get_context()->line_sprites = 0;
|
ppu_get_context()->line_sprites = 0;
|
||||||
ppu_get_context()->line_sprite_count = 0;
|
ppu_get_context()->line_sprite_count = 0;
|
||||||
@ -112,6 +112,7 @@ void ppu_mode_xfer() {
|
|||||||
|
|
||||||
if(LCDS_STAT_INT(SS_HBLANK)) {
|
if(LCDS_STAT_INT(SS_HBLANK)) {
|
||||||
cpu_request_interrupt(IT_LCD_STAT);
|
cpu_request_interrupt(IT_LCD_STAT);
|
||||||
|
printf("hblank!\n");
|
||||||
}
|
}
|
||||||
ppu_get_context()->rendering_window = false;
|
ppu_get_context()->rendering_window = false;
|
||||||
}
|
}
|
||||||
@ -123,7 +124,18 @@ void ppu_mode_vblank() {
|
|||||||
|
|
||||||
if(lcd_get_context()->ly >= LINES_PER_FRAME) {
|
if(lcd_get_context()->ly >= LINES_PER_FRAME) {
|
||||||
LCDS_MODE_SET(MODE_OAM);
|
LCDS_MODE_SET(MODE_OAM);
|
||||||
|
if(LCDS_STAT_INT(SS_OAM)) {
|
||||||
|
cpu_request_interrupt(IT_LCD_STAT);
|
||||||
|
}
|
||||||
lcd_get_context()->ly = 0;
|
lcd_get_context()->ly = 0;
|
||||||
|
if(lcd_get_context()->ly == lcd_get_context()->ly_compare) {
|
||||||
|
LCDS_LYC_SET(1);
|
||||||
|
if(LCDS_STAT_INT(SS_LYC)) {
|
||||||
|
cpu_request_interrupt(IT_LCD_STAT);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
LCDS_LYC_SET(0);
|
||||||
|
}
|
||||||
ppu_get_context()->window_line = 0;
|
ppu_get_context()->window_line = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -156,6 +168,8 @@ void ppu_mode_hblank() {
|
|||||||
|
|
||||||
if(frame_time < ppu_get_context()->target_frame_time) {
|
if(frame_time < ppu_get_context()->target_frame_time) {
|
||||||
delay((ppu_get_context()->target_frame_time - frame_time));
|
delay((ppu_get_context()->target_frame_time - frame_time));
|
||||||
|
} else if(frame_time > ppu_get_context()->target_frame_time) {
|
||||||
|
//printf("Frame timing missed!\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
while(ppu_get_context()->paused) {
|
while(ppu_get_context()->paused) {
|
||||||
@ -182,6 +196,9 @@ void ppu_mode_hblank() {
|
|||||||
|
|
||||||
} else {
|
} else {
|
||||||
LCDS_MODE_SET(MODE_OAM);
|
LCDS_MODE_SET(MODE_OAM);
|
||||||
|
if(LCDS_STAT_INT(SS_OAM)) {
|
||||||
|
cpu_request_interrupt(IT_LCD_STAT);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ppu_get_context()->line_ticks = 0;
|
ppu_get_context()->line_ticks = 0;
|
||||||
|
35
lib/ui.c
35
lib/ui.c
@ -5,10 +5,15 @@
|
|||||||
#include <bus.h>
|
#include <bus.h>
|
||||||
#include <audio.h>
|
#include <audio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <lcd.h>
|
||||||
|
#include <cpu.h>
|
||||||
|
#include <cart.h>
|
||||||
|
|
||||||
#include <SDL.h>
|
#include <SDL.h>
|
||||||
#include <SDL_ttf.h>
|
#include <SDL_ttf.h>
|
||||||
|
|
||||||
|
#define VRAM_DEBUG 0
|
||||||
|
|
||||||
SDL_Window *sdlWindow;
|
SDL_Window *sdlWindow;
|
||||||
SDL_Renderer *sdlRenderer;
|
SDL_Renderer *sdlRenderer;
|
||||||
SDL_Texture *sdlTexture;
|
SDL_Texture *sdlTexture;
|
||||||
@ -40,7 +45,7 @@ void ui_init(){
|
|||||||
SDL_TEXTUREACCESS_STREAMING,
|
SDL_TEXTUREACCESS_STREAMING,
|
||||||
SCREEN_WIDTH,
|
SCREEN_WIDTH,
|
||||||
SCREEN_HEIGHT);
|
SCREEN_HEIGHT);
|
||||||
|
#if VRAM_DEBUG == 1
|
||||||
SDL_CreateWindowAndRenderer(16 * 8 * scale, 32 * 8 * scale, 0, &sdlDebugWindow, &sdlDebugRenderer);
|
SDL_CreateWindowAndRenderer(16 * 8 * scale, 32 * 8 * scale, 0, &sdlDebugWindow, &sdlDebugRenderer);
|
||||||
debugScreen = SDL_CreateRGBSurface(0, (16 * 8 * scale) + (16 * scale),
|
debugScreen = SDL_CreateRGBSurface(0, (16 * 8 * scale) + (16 * scale),
|
||||||
(32 * 8 * scale) + (64 * scale), 32,
|
(32 * 8 * scale) + (64 * scale), 32,
|
||||||
@ -56,9 +61,10 @@ void ui_init(){
|
|||||||
int x, y;
|
int x, y;
|
||||||
SDL_GetWindowPosition(sdlWindow, &x, &y);
|
SDL_GetWindowPosition(sdlWindow, &x, &y);
|
||||||
SDL_SetWindowPosition(sdlDebugWindow, x+SCREEN_WIDTH, y);
|
SDL_SetWindowPosition(sdlDebugWindow, x+SCREEN_WIDTH, y);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned long tile_colors[4] = {0xFFFFFFFF, 0xFFAAAAAA, 0xFF555555, 0xFF000000};
|
static unsigned long tile_colors[4] = {0xFF9ABB1B, 0xFF8AAB19, 0xFF2F6130, 0xFF0E370F};
|
||||||
|
|
||||||
void display_tile(SDL_Surface *surface, u16 startLocation, u16 tileNum, int x, int y) {
|
void display_tile(SDL_Surface *surface, u16 startLocation, u16 tileNum, int x, int y) {
|
||||||
SDL_Rect rc;
|
SDL_Rect rc;
|
||||||
@ -277,9 +283,23 @@ void ui_update() {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SDL_RenderPresent(sdlRenderer);
|
char cpu_buffer[1024];
|
||||||
|
sprintf_s(cpu_buffer, 1024, "PC: %04X, SP: %04X, AF: %02X%02X, BC: %02X%02X, DE: %02X%02X, HL: %02X%02X, Cart_Bank: %02d", cpu_get_context()->regs.pc, cpu_get_context()->regs.sp, cpu_get_context()->regs.a, cpu_get_context()->regs.f, cpu_get_context()->regs.b, cpu_get_context()->regs.c, cpu_get_context()->regs.d, cpu_get_context()->regs.e, cpu_get_context()->regs.h, cpu_get_context()->regs.l, cart_get_rom_bank());
|
||||||
|
message = TTF_RenderText_Solid(sans, cpu_buffer, text_color);
|
||||||
|
messageTexture = SDL_CreateTextureFromSurface(sdlRenderer, message);
|
||||||
|
messageRect.x = 0;
|
||||||
|
messageRect.y = (YRES * scale) + 10;
|
||||||
|
messageRect.w = 500;
|
||||||
|
messageRect.h = 20;
|
||||||
|
SDL_RenderCopy(sdlRenderer, messageTexture, NULL, &messageRect);
|
||||||
|
SDL_SetRenderDrawColor(sdlRenderer, 0, 255, 0, 255);
|
||||||
|
SDL_FreeSurface(message);
|
||||||
|
SDL_DestroyTexture(messageTexture);
|
||||||
|
|
||||||
|
SDL_RenderPresent(sdlRenderer);
|
||||||
|
#if VRAM_DEBUG == 1
|
||||||
update_debug_window();
|
update_debug_window();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void ui_on_key(bool down, u32 key_code) {
|
void ui_on_key(bool down, u32 key_code) {
|
||||||
@ -305,6 +325,14 @@ void ui_on_key(bool down, u32 key_code) {
|
|||||||
printf("Resumed Emulation\n");
|
printf("Resumed Emulation\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if(key_code == SDLK_d && down == true) {
|
||||||
|
ppu_get_context()->debug = !ppu_get_context()->debug;
|
||||||
|
if(ppu_get_context()->debug) {
|
||||||
|
printf("PPU Debug Enabled\n");
|
||||||
|
} else {
|
||||||
|
printf("PPU Debug Disabled\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
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;
|
||||||
@ -316,6 +344,7 @@ void ui_on_key(bool down, u32 key_code) {
|
|||||||
case SDLK_LEFT: gamepad_get_state()->left = down; break;
|
case SDLK_LEFT: gamepad_get_state()->left = down; break;
|
||||||
case SDLK_RIGHT: gamepad_get_state()->right = down; break;
|
case SDLK_RIGHT: gamepad_get_state()->right = down; break;
|
||||||
}
|
}
|
||||||
|
gamepad_int_update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user