Working on apu

This commit is contained in:
Samuel Walker 2025-02-17 21:22:13 -07:00
parent 4823aeae93
commit 020feb2a6f
Signed by: piwalker
GPG Key ID: 616B1928705EA4C9
7 changed files with 100 additions and 31 deletions

View File

@ -7,6 +7,7 @@ typedef struct {
bool running; bool running;
bool die; bool die;
u64 ticks; u64 ticks;
const char *app_path;
} emu_context; } emu_context;
int emu_run(int, char**); int emu_run(int, char**);

View File

@ -80,6 +80,8 @@ typedef struct {
bool rendering_window; bool rendering_window;
u32 target_frame_time; u32 target_frame_time;
bool paused;
bool frame;
} ppu_context; } ppu_context;
void ppu_init(); void ppu_init();

View File

@ -1,6 +1,7 @@
#include <audio.h> #include <audio.h>
#include <emu.h> #include <emu.h>
#include <ppu.h>
#include <portaudio.h> #include <portaudio.h>
#include <pa_ringbuffer.h> #include <pa_ringbuffer.h>
@ -22,12 +23,14 @@ static float audio_time = 0;
static float wave_time = 0; static float wave_time = 0;
static float lfsr_timer = 0; static float lfsr_timer = 0;
static float lfsr_clock = LFSR_BASE_CLOCK; static float lfsr_clock = LFSR_BASE_CLOCK;
static float lfsr_clock_buffer = LFSR_BASE_CLOCK;
static float left_cap = 0.0f; static float left_cap = 0.0f;
static float right_cap = 0.0f; static float right_cap = 0.0f;
static int history_timer = 0; static int history_timer = 0;
const int history_interval = 5; const int history_interval = 5;
static int lfsr_clocks = 0;
const u8 square_sample_00[8] = { const u8 square_sample_00[8] = {
0x0, 0x0,
@ -87,6 +90,11 @@ static int audio_callback(const void* input_uffer, void *output_buffer,
void *userData ) { void *userData ) {
float *out = (float *)output_buffer; float *out = (float *)output_buffer;
for(int i = 0; i < framesPerBuffer; i++) { for(int i = 0; i < framesPerBuffer; i++) {
if(ppu_get_context()->paused) {
*out++ = 0;
*out++ = 0;
continue;
}
float left = 0; float left = 0;
float right = 0; float right = 0;
audio_time += TIME_PER_SAMPLE; audio_time += TIME_PER_SAMPLE;
@ -118,17 +126,29 @@ static int audio_callback(const void* input_uffer, void *output_buffer,
} }
lfsr_timer += TIME_PER_SAMPLE; lfsr_timer += TIME_PER_SAMPLE;
for(;lfsr_timer >= lfsr_clock;lfsr_timer -= lfsr_clock) { for(;lfsr_timer >= lfsr_clock;lfsr_timer -= lfsr_clock) {
if(ctx.ch4_enable) { //if(ctx.ch4_enable) {
lfsr_timer = 0; lfsr_clocks++;
u8 new = !((ctx.ch4_lfsr & 0b1) ^ ((ctx.ch4_lfsr >> 1) & 0b1)) & 0b1; lfsr_clock = lfsr_clock_buffer;
ctx.ch4_lfsr |= (new << 15); //lfsr_timer = 0;
if(ctx.ch4_lfsr_width) { //u16 new = ~((ctx.ch4_lfsr & 0b1) ^ ((ctx.ch4_lfsr & 0b10) >> 1)) & 0b1;
ctx.ch4_lfsr &= ~(1 << 7); //ctx.ch4_lfsr &= ~(1 << 15);
ctx.ch4_lfsr |= (new << 7); //ctx.ch4_lfsr |= ((new << 15) & 0x8000);
} //printf("new bit: %02X\n", (new << 15));
ctx.ch4_lfsr = ctx.ch4_lfsr >> 1; //if(ctx.ch4_lfsr_width) {
// ctx.ch4_lfsr &= ~(1 << 7);
// ctx.ch4_lfsr |= (new << 7);
//}
//ctx.ch4_lfsr = ctx.ch4_lfsr >> 1;
//printf("lfsr: %02X, bit: %d\n", ctx.ch4_lfsr, new); //printf("lfsr: %02X, bit: %d\n", ctx.ch4_lfsr, new);
unsigned bit_mask = ctx.ch4_lfsr_width ? 0x4040 : 0x4000;
bool new_bit = (ctx.ch4_lfsr ^ (ctx.ch4_lfsr >> 1) ^ 1) & 1;
ctx.ch4_lfsr >>= 1;
if(new_bit) {
ctx.ch4_lfsr |= bit_mask;
} else {
ctx.ch4_lfsr &= ~bit_mask;
} }
//}
} }
float sq1_val = 0; float sq1_val = 0;
float sq2_val = 0; float sq2_val = 0;
@ -206,7 +226,7 @@ static int audio_callback(const void* input_uffer, void *output_buffer,
if(ctx.ch4_dac){ if(ctx.ch4_dac){
ch4_val = -1; ch4_val = -1;
if(ctx.ch4_enable) { if(ctx.ch4_enable) {
ch4_val = (ctx.ch4_lfsr & 0b1) ? (((float)ctx.ch4_volume - 7.5f)/7.5f) : -1.0f; ch4_val = ((ctx.ch4_lfsr & 0b1) == 0b1) ? (((float)ctx.ch4_volume - 7.5f)/7.5f) : -1.0f;
if(ctx.ch4_left) { if(ctx.ch4_left) {
left += ch4_val; left += ch4_val;
//printf("left: %d\n", ctx.ch3_volume); //printf("left: %d\n", ctx.ch3_volume);
@ -248,7 +268,16 @@ static int audio_callback(const void* input_uffer, void *output_buffer,
right_out /= 4; right_out /= 4;
if(left_out < -1.0f) { if(left_out < -1.0f) {
printf("Uh Oh! %f\n", left_out); left_out = -1;
}
if(left_out > 1.0f) {
left_out = 1;
}
if(right_out < -1.0f) {
right_out = -1;
}
if(right_out > 1.0f) {
right_out = 1;
} }
history_timer++; history_timer++;
if(history_timer >= history_interval){ if(history_timer >= history_interval){
@ -382,6 +411,7 @@ void sq1_sweep() {
static int change = 1; static int change = 1;
static u32 ticks = 0; static u32 ticks = 0;
static u32 start, end = 0;
void audio_tick(){ void audio_tick(){
u32 prev_ticks = ticks; u32 prev_ticks = ticks;
@ -415,7 +445,7 @@ void audio_tick(){
if(ctx.ch4_len_enable && ctx.ch4_enable) { if(ctx.ch4_len_enable && ctx.ch4_enable) {
ctx.ch4_len++; ctx.ch4_len++;
//printf("Ch4 env: %02X\n", ctx.ch4_len); //printf("Ch4 len: %02X\n", ctx.ch4_len);
if(ctx.ch4_len >= 64) { if(ctx.ch4_len >= 64) {
ctx.ch4_len = 0; ctx.ch4_len = 0;
ctx.ch4_enable = false; ctx.ch4_enable = false;
@ -454,19 +484,20 @@ void audio_tick(){
} }
} }
if(ctx.ch4_env_pace != 0){ //if(ctx.ch4_env_pace != 0){
ctx.ch4_env_timer++; ctx.ch4_env_timer--;
if(ctx.ch4_env_timer >= ctx.ch4_env_pace) { if(ctx.ch4_env_timer <= 0) {
ctx.ch4_env_timer = 0; ctx.ch4_env_timer = ctx.ch4_env_pace_buffer != 0 ? ctx.ch4_env_pace_buffer : 8;
if((ctx.ch4_env_direction && ctx.ch4_volume != 15) || (!ctx.ch4_env_direction && ctx.ch4_volume != 0)){ if(ctx.ch4_env_pace != 0 && ((ctx.ch4_env_direction && ctx.ch4_volume != 15) || (!ctx.ch4_env_direction && ctx.ch4_volume != 0))){
ctx.ch4_volume += ctx.ch4_env_direction ? 1 : -1; ctx.ch4_volume += ctx.ch4_env_direction ? 1 : -1;
//printf("Noise Vol: %02X\n", ctx.ch4_volume);
if(ctx.ch4_volume < 0) if(ctx.ch4_volume < 0)
ctx.ch4_volume = 0; ctx.ch4_volume = 0;
if(ctx.ch4_volume > 15) if(ctx.ch4_volume > 15)
ctx.ch4_volume = 15; ctx.ch4_volume = 15;
} }
} }
} //}
} }
@ -528,12 +559,15 @@ void enable_noise() {
if(!ctx.ch4_dac){ if(!ctx.ch4_dac){
return; return;
} }
start = get_ticks();
ctx.ch4_enable = true; ctx.ch4_enable = true;
ctx.ch4_env_timer = 0; ctx.ch4_env_timer = ctx.ch4_env_pace_buffer != 0 ? ctx.ch4_env_pace_buffer : 8;
ctx.ch4_env_direction = ctx.ch4_env_direction_buffer; ctx.ch4_env_direction = ctx.ch4_env_direction_buffer;
ctx.ch4_env_pace = ctx.ch4_env_pace_buffer; ctx.ch4_env_pace = ctx.ch4_env_pace_buffer;
ctx.ch4_volume = ctx.ch4_initial_volume; ctx.ch4_volume = ctx.ch4_initial_volume;
ctx.ch4_lfsr = 0; ctx.ch4_lfsr = 0;
lfsr_clock = lfsr_clock_buffer;
lfsr_timer = 0;
} }
u8 audio_read(u16 address) { u8 audio_read(u16 address) {
@ -928,6 +962,7 @@ void audio_write(u16 address, u8 value){
ctx.ch4_len = ctx.ch4_initial_len; ctx.ch4_len = ctx.ch4_initial_len;
ctx.ch4_len_fz = false; ctx.ch4_len_fz = false;
//printf("ch4 len: %02X\n", ctx.ch4_len); //printf("ch4 len: %02X\n", ctx.ch4_len);
printf("Write Ch4 Len: %02X\n", value);
} }
if(address == 0xFF21) { if(address == 0xFF21) {
@ -940,15 +975,18 @@ void audio_write(u16 address, u8 value){
} else { } else {
ctx.ch4_dac = true; ctx.ch4_dac = true;
} }
printf("Write Ch4 env: %02X\n", value);
} }
if(address == 0xFF22) { if(address == 0xFF22) {
ctx.ch4_clock_shift = (value >> 4); ctx.ch4_clock_shift = (value >> 4) & 0xF;
ctx.ch4_lfsr_width = (value & 0x08); ctx.ch4_lfsr_width = (value & 0x08);
ctx.ch4_clock_divider = value & 0b111; ctx.ch4_clock_divider = value & 0b111;
float div = (ctx.ch4_clock_divider == 0 ? 0.5f : ctx.ch4_clock_divider); float div = (ctx.ch4_clock_divider == 0 ? 0.5f : (float)ctx.ch4_clock_divider);
float lfsr_rate = (LFSR_BASE_CLOCK) / (div * (1 << ctx.ch4_clock_shift)); float lfsr_rate = (LFSR_BASE_CLOCK) / (div * (float)(1 << ctx.ch4_clock_shift));
lfsr_clock = 1.0f / (lfsr_rate/1000.0f/1000.0f); lfsr_clock_buffer = 1.0f / (lfsr_rate/1000.0f/1000.0f);
//printf("Ch4 clock: Shift: %01X, Width: %d, Div: %f (%01X), Rate: %f, Clock %f\n", ctx.ch4_clock_shift, ctx.ch4_lfsr_width, div, ctx.ch4_clock_divider, lfsr_rate, lfsr_clock);
printf("Write Ch4 Clock: %02X\n", value);
} }
if(address == 0xFF23) { if(address == 0xFF23) {
@ -975,5 +1013,6 @@ void audio_write(u16 address, u8 value){
if(value & 0x80) { if(value & 0x80) {
enable_noise(); enable_noise();
} }
printf("Write Ch4 Trigger: %02X\n", value);
} }
} }

View File

@ -71,6 +71,7 @@ int emu_run(int argc, char **argv) {
} }
printf("Cart loaded..\n"); printf("Cart loaded..\n");
ctx.app_path = argv[0];
ui_init(); ui_init();
#ifdef _WIN32 #ifdef _WIN32

View File

@ -158,6 +158,14 @@ void ppu_mode_hblank() {
delay((ppu_get_context()->target_frame_time - frame_time)); delay((ppu_get_context()->target_frame_time - frame_time));
} }
while(ppu_get_context()->paused) {
delay(10);
if(ppu_get_context()->frame){
ppu_get_context()->frame = false;
break;
}
}
if (end - start_timer >= 1000) { if (end - start_timer >= 1000) {
u32 fps = frame_count; u32 fps = frame_count;
start_timer = end; start_timer = end;

View File

@ -39,7 +39,7 @@ void timer_tick() {
} }
} }
if((prev_div & (1 << 13)) && (!(ctx.div & (1 << 13)))){ if((prev_div & (1 << 12)) && (!(ctx.div & (1 << 12)))){
audio_tick(); audio_tick();
} }

View File

@ -4,6 +4,7 @@
#include <gamepad.h> #include <gamepad.h>
#include <bus.h> #include <bus.h>
#include <audio.h> #include <audio.h>
#include <string.h>
#include <SDL.h> #include <SDL.h>
#include <SDL_ttf.h> #include <SDL_ttf.h>
@ -131,7 +132,11 @@ void ui_update() {
SDL_UpdateTexture(sdlTexture, NULL, screen->pixels, screen->pitch); SDL_UpdateTexture(sdlTexture, NULL, screen->pixels, screen->pitch);
SDL_RenderClear(sdlRenderer); SDL_RenderClear(sdlRenderer);
SDL_RenderCopy(sdlRenderer, sdlTexture, NULL, NULL); SDL_RenderCopy(sdlRenderer, sdlTexture, NULL, NULL);
TTF_Font* sans = TTF_OpenFont("Sans.ttf", 24); char buffer[1024];
strcpy(buffer, emu_get_context()->app_path);
*strrchr(buffer, '\\') = 0;
strcat(buffer,"/Sans.ttf");
TTF_Font* sans = TTF_OpenFont(buffer, 24);
if ( !sans ) { if ( !sans ) {
printf("Failed to load font: %s\n", TTF_GetError()); printf("Failed to load font: %s\n", TTF_GetError());
} }
@ -289,6 +294,19 @@ void ui_on_key(bool down, u32 key_code) {
} }
printf("target frame time: %d\n", ppu_get_context()->target_frame_time); printf("target frame time: %d\n", ppu_get_context()->target_frame_time);
} }
if(ppu_get_context()->paused) {
if(key_code == SDLK_PERIOD && down == true){
ppu_get_context()->frame = true;
}
}
if(key_code == SDLK_p && down == true) {
ppu_get_context()->paused = !ppu_get_context()->paused;
if(ppu_get_context()->paused) {
printf("Paused Emulation\n");
} else {
printf("Resumed Emulation\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;