Add APU-related debugger commands
This change includes making one of the APU functions public
This commit is contained in:
parent
795823e372
commit
40f83c8f25
@ -21,7 +21,7 @@ static void refresh_channel(GB_gameboy_t *gb, unsigned index, unsigned cycles_of
|
|||||||
gb->apu_output.last_update[index] = gb->apu_output.cycles_since_render + cycles_offset;
|
gb->apu_output.last_update[index] = gb->apu_output.cycles_since_render + cycles_offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool is_DAC_enabled(GB_gameboy_t *gb, unsigned index)
|
bool GB_apu_is_DAC_enabled(GB_gameboy_t *gb, unsigned index)
|
||||||
{
|
{
|
||||||
switch (index) {
|
switch (index) {
|
||||||
case GB_SQUARE_1:
|
case GB_SQUARE_1:
|
||||||
@ -42,7 +42,7 @@ static bool is_DAC_enabled(GB_gameboy_t *gb, unsigned index)
|
|||||||
|
|
||||||
static void update_sample(GB_gameboy_t *gb, unsigned index, int8_t value, unsigned cycles_offset)
|
static void update_sample(GB_gameboy_t *gb, unsigned index, int8_t value, unsigned cycles_offset)
|
||||||
{
|
{
|
||||||
if (!is_DAC_enabled(gb, index)) {
|
if (!GB_apu_is_DAC_enabled(gb, index)) {
|
||||||
value = gb->apu.samples[index];
|
value = gb->apu.samples[index];
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -73,7 +73,7 @@ static void render(GB_gameboy_t *gb, bool no_downsampling, GB_sample_t *dest)
|
|||||||
UNROLL
|
UNROLL
|
||||||
for (unsigned i = 0; i < GB_N_CHANNELS; i++) {
|
for (unsigned i = 0; i < GB_N_CHANNELS; i++) {
|
||||||
double multiplier = CH_STEP;
|
double multiplier = CH_STEP;
|
||||||
if (!is_DAC_enabled(gb, i)) {
|
if (!GB_apu_is_DAC_enabled(gb, i)) {
|
||||||
gb->apu_output.dac_discharge[i] -= ((double) DAC_DECAY_SPEED) / gb->apu_output.sample_rate;
|
gb->apu_output.dac_discharge[i] -= ((double) DAC_DECAY_SPEED) / gb->apu_output.sample_rate;
|
||||||
if (gb->apu_output.dac_discharge[i] < 0) {
|
if (gb->apu_output.dac_discharge[i] < 0) {
|
||||||
multiplier = 0;
|
multiplier = 0;
|
||||||
|
@ -160,6 +160,7 @@ size_t GB_apu_get_current_buffer_length(GB_gameboy_t *gb);
|
|||||||
void GB_set_highpass_filter_mode(GB_gameboy_t *gb, GB_highpass_mode_t mode);
|
void GB_set_highpass_filter_mode(GB_gameboy_t *gb, GB_highpass_mode_t mode);
|
||||||
|
|
||||||
#ifdef GB_INTERNAL
|
#ifdef GB_INTERNAL
|
||||||
|
bool GB_apu_is_DAC_enabled(GB_gameboy_t *gb, unsigned index);
|
||||||
void GB_apu_write(GB_gameboy_t *gb, uint8_t reg, uint8_t value);
|
void GB_apu_write(GB_gameboy_t *gb, uint8_t reg, uint8_t value);
|
||||||
uint8_t GB_apu_read(GB_gameboy_t *gb, uint8_t reg);
|
uint8_t GB_apu_read(GB_gameboy_t *gb, uint8_t reg);
|
||||||
void GB_apu_div_event(GB_gameboy_t *gb);
|
void GB_apu_div_event(GB_gameboy_t *gb);
|
||||||
|
170
Core/debugger.c
170
Core/debugger.c
@ -1570,6 +1570,172 @@ static bool lcd(GB_gameboy_t *gb, char *arguments, char *modifiers, const debugg
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool apu(GB_gameboy_t *gb, char *arguments, char *modifiers, const debugger_command_t *command)
|
||||||
|
{
|
||||||
|
NO_MODIFIERS
|
||||||
|
if (strlen(lstrip(arguments))) {
|
||||||
|
print_usage(gb, command);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
GB_log(gb, "Current state: ");
|
||||||
|
if(!gb->apu.global_enable) {
|
||||||
|
GB_log(gb, "Disabled\n");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
GB_log(gb, "Enabled\n");
|
||||||
|
for(uint8_t channel = 0; channel < GB_N_CHANNELS; channel++) {
|
||||||
|
GB_log(gb, "CH%u is %s, DAC %s; current sample = 0x%x\n", channel + 1,
|
||||||
|
gb->apu.is_active[channel] ? "active " : "inactive",
|
||||||
|
GB_apu_is_DAC_enabled(gb, channel) ? "active " : "inactive",
|
||||||
|
gb->apu.samples[channel]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GB_log(gb, "SO1 (left output): volume %u,", gb->io_registers[GB_IO_NR50] & 0x07);
|
||||||
|
if(gb->io_registers[GB_IO_NR51] & 0x0f) {
|
||||||
|
for(uint8_t channel = 0, mask = 0x01; channel < GB_N_CHANNELS; channel++, mask <<= 1) {
|
||||||
|
if(gb->io_registers[GB_IO_NR51] & mask) {
|
||||||
|
GB_log(gb, " CH%u", channel + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
GB_log(gb, " no channels");
|
||||||
|
}
|
||||||
|
GB_log(gb, "%s\n", gb->io_registers[GB_IO_NR50] & 0x80 ? " VIN": "");
|
||||||
|
|
||||||
|
GB_log(gb, "SO2 (right output): volume %u,", gb->io_registers[GB_IO_NR50] & 0x70 >> 4);
|
||||||
|
if(gb->io_registers[GB_IO_NR51] & 0xf0) {
|
||||||
|
for(uint8_t channel = 0, mask = 0x10; channel < GB_N_CHANNELS; channel++, mask <<= 1) {
|
||||||
|
if(gb->io_registers[GB_IO_NR51] & mask) {
|
||||||
|
GB_log(gb, " CH%u", channel + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
GB_log(gb, " no channels");
|
||||||
|
}
|
||||||
|
GB_log(gb, "%s\n", gb->io_registers[GB_IO_NR50] & 0x80 ? " VIN": "");
|
||||||
|
|
||||||
|
|
||||||
|
for(uint8_t channel = GB_SQUARE_1; channel <= GB_SQUARE_2; channel++) {
|
||||||
|
GB_log(gb, "\nCH%u:\n", channel + 1);
|
||||||
|
GB_log(gb, " Current volume: %u, current sample length: %u APU ticks (next in %u ticks)\n",
|
||||||
|
gb->apu.square_channels[channel].current_volume,
|
||||||
|
gb->apu.square_channels[channel].sample_length,
|
||||||
|
gb->apu.square_channels[channel].sample_countdown);
|
||||||
|
|
||||||
|
uint8_t nrx2 = gb->io_registers[channel == GB_SQUARE_1? GB_IO_NR12 : GB_IO_NR22];
|
||||||
|
GB_log(gb, " %u 256 Hz ticks till next volume %screase (out of %u)\n",
|
||||||
|
gb->apu.square_channels[channel].volume_countdown,
|
||||||
|
nrx2 & 8 ? "in" : "de",
|
||||||
|
nrx2 & 7);
|
||||||
|
|
||||||
|
uint8_t duty = gb->io_registers[channel == GB_SQUARE_1? GB_IO_NR11 :GB_IO_NR21] >> 6;
|
||||||
|
GB_log(gb, " Duty cycle %s%% (%s), current index %u/8%s\n",
|
||||||
|
(char*[]){"12.5", " 25", " 50", " 75"}[duty],
|
||||||
|
(char*[]){"_______-", "-______-", "-____---", "_------_"}[duty],
|
||||||
|
gb->apu.square_channels[channel].current_sample_index & 0x7f,
|
||||||
|
gb->apu.square_channels[channel].current_sample_index >> 7 ? " (suppressed)" : "");
|
||||||
|
|
||||||
|
if(channel == GB_SQUARE_1) {
|
||||||
|
GB_log(gb, " Frequency sweep %s and %s (next in %u APU ticks)\n",
|
||||||
|
gb->apu.sweep_enabled? "active" : "inactive",
|
||||||
|
gb->apu.sweep_decreasing? "decreasing" : "increasing",
|
||||||
|
gb->apu.square_sweep_calculate_countdown);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(gb->apu.square_channels[channel].length_enabled) {
|
||||||
|
GB_log(gb, " Channel will end in %u 256 Hz ticks\n",
|
||||||
|
gb->apu.square_channels[channel].pulse_length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
GB_log(gb, "\nCH3:\n");
|
||||||
|
GB_log(gb, " Wave:");
|
||||||
|
for(uint8_t i = 0; i < 32; i++) {
|
||||||
|
GB_log(gb, "%s%X", i%4?"":" ", gb->apu.wave_channel.wave_form[i]);
|
||||||
|
}
|
||||||
|
GB_log(gb, ", has %sjust been read\n", gb->apu.wave_channel.wave_form_just_read? "": "not ");
|
||||||
|
GB_log(gb, " Current position: %u\n", gb->apu.wave_channel.current_sample_index);
|
||||||
|
|
||||||
|
GB_log(gb, " Volume %s (right-shifted %ux)\n",
|
||||||
|
(char*[]){"100%", "50%", "25%", NULL, "muted"}[gb->apu.wave_channel.shift],
|
||||||
|
gb->apu.wave_channel.shift);
|
||||||
|
|
||||||
|
GB_log(gb, " Current sample length: %u APU ticks (next in %u ticks)\n",
|
||||||
|
gb->apu.wave_channel.sample_length,
|
||||||
|
gb->apu.wave_channel.sample_countdown);
|
||||||
|
|
||||||
|
if(gb->apu.wave_channel.length_enabled) {
|
||||||
|
GB_log(gb, " Channel will end in %u 256 Hz ticks\n",
|
||||||
|
gb->apu.wave_channel.pulse_length);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
GB_log(gb, "\nCH4:\n");
|
||||||
|
GB_log(gb, " Current volume: %u, current sample length: %u APU ticks (next in %u ticks)\n",
|
||||||
|
gb->apu.noise_channel.current_volume,
|
||||||
|
gb->apu.noise_channel.sample_length,
|
||||||
|
gb->apu.noise_channel.sample_countdown);
|
||||||
|
|
||||||
|
GB_log(gb, " %u 256 Hz ticks till next volume %screase (out of %u)\n",
|
||||||
|
gb->apu.noise_channel.volume_countdown,
|
||||||
|
gb->io_registers[GB_IO_NR42] & 8 ? "in" : "de",
|
||||||
|
gb->io_registers[GB_IO_NR42] & 7);
|
||||||
|
|
||||||
|
GB_log(gb, " LFSR in %u-step mode, current value %%",
|
||||||
|
gb->apu.noise_channel.narrow? 7 : 15);
|
||||||
|
for(uint16_t lfsr = gb->apu.noise_channel.lfsr, i = 15; i--; lfsr <<= 1) {
|
||||||
|
GB_log(gb, "%u%s", (lfsr >> 14) & 1, i%4 ? "" : " ");
|
||||||
|
}
|
||||||
|
|
||||||
|
if(gb->apu.noise_channel.length_enabled) {
|
||||||
|
GB_log(gb, " Channel will end in %u 256 Hz ticks\n",
|
||||||
|
gb->apu.noise_channel.pulse_length);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
GB_log(gb, "\n\nReminder: APU ticks are @ 2 MiHz\n");
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool wave(GB_gameboy_t *gb, char *arguments, char *modifiers, const debugger_command_t *command)
|
||||||
|
{
|
||||||
|
if (strlen(lstrip(arguments)) || (modifiers && !strchr("fcl", modifiers[0]))) {
|
||||||
|
print_usage(gb, command);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t shift_amount = 1, mask;
|
||||||
|
if(modifiers) {
|
||||||
|
switch(modifiers[0]) {
|
||||||
|
case 'c':
|
||||||
|
shift_amount = 2;
|
||||||
|
break;
|
||||||
|
case 'l':
|
||||||
|
shift_amount = 8;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mask = (0xf << (shift_amount - 1)) & 0xf;
|
||||||
|
|
||||||
|
for(int8_t cur_val = 0xf & mask; cur_val >= 0; cur_val -= shift_amount) {
|
||||||
|
for(uint8_t i = 0; i < 32; i++) {
|
||||||
|
if((gb->apu.wave_channel.wave_form[i] & mask) == cur_val) {
|
||||||
|
GB_log(gb, "%X", gb->apu.wave_channel.wave_form[i]);
|
||||||
|
} else {
|
||||||
|
GB_log(gb, "%c", i%4 == 2 ? '-' : ' ');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
GB_log(gb, "\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static bool help(GB_gameboy_t *gb, char *arguments, char *modifiers, const debugger_command_t *command);
|
static bool help(GB_gameboy_t *gb, char *arguments, char *modifiers, const debugger_command_t *command);
|
||||||
|
|
||||||
#define HELP_NEWLINE "\n "
|
#define HELP_NEWLINE "\n "
|
||||||
@ -1587,6 +1753,10 @@ static const debugger_command_t commands[] = {
|
|||||||
{"registers", 1, registers, "Print values of processor registers and other important registers"},
|
{"registers", 1, registers, "Print values of processor registers and other important registers"},
|
||||||
{"cartridge", 2, mbc, "Displays information about the MBC and cartridge"},
|
{"cartridge", 2, mbc, "Displays information about the MBC and cartridge"},
|
||||||
{"mbc", 3, }, /* Alias */
|
{"mbc", 3, }, /* Alias */
|
||||||
|
{"apu", 3, apu, "Displays information about the current state of the audio chip"},
|
||||||
|
{"wave", 3, wave, "Prints a visual representation of the wave RAM" HELP_NEWLINE
|
||||||
|
"Modifiers can be used for a (f)ull print (the default)," HELP_NEWLINE
|
||||||
|
"a more (c)ompact one, or a one-(l)iner"},
|
||||||
{"lcd", 3, lcd, "Displays information about the current state of the LCD controller"},
|
{"lcd", 3, lcd, "Displays information about the current state of the LCD controller"},
|
||||||
{"palettes", 3, palettes, "Displays the current CGB palettes"},
|
{"palettes", 3, palettes, "Displays the current CGB palettes"},
|
||||||
{"breakpoint", 1, breakpoint, "Add a new breakpoint at the specified address/expression" HELP_NEWLINE
|
{"breakpoint", 1, breakpoint, "Add a new breakpoint at the specified address/expression" HELP_NEWLINE
|
||||||
|
Loading…
Reference in New Issue
Block a user