add preliminary apu register support

This commit is contained in:
Vineet K 2024-08-31 22:24:33 -04:00
parent c0679b404d
commit 279478f16f
4 changed files with 171 additions and 4 deletions

View File

@ -1,7 +1,7 @@
CFLAGS = -O2 -Wall -Wextra -pedantic -Wno-unused-parameter CFLAGS = -O2 -Wall -Wextra -pedantic -Wno-unused-parameter
nes: nes:
${CC} ${CFLAGS} -o nes cpu.c rom.c ppu.c ${CC} ${CFLAGS} -o nes cpu.c rom.c ppu.c apu.c
test: nes test: nes
./nes ${HOME}/src/other/nes-test-roms/other/nestest.nes ./nes ${HOME}/src/other/nes-test-roms/other/nestest.nes

55
apu.c Normal file
View File

@ -0,0 +1,55 @@
#include <stdio.h>
#include <string.h>
#include "apu.h"
struct apu apu = {0};
void
apu_init(void)
{
memset(&apu, 0, sizeof(apu));
}
uint8_t
apu_read(uint16_t addr)
{
switch (addr) {
/* pulse1 */
case 0x4000:
return (apu.pulse1.duty << 6) | (apu.pulse1.envelope << 5)
| (apu.pulse1.const_vol << 4) | apu.pulse1.envelope_vol;
case 0x4001:
return (apu.pulse1.sweep_enable << 7) | (apu.pulse1.sweep_period << 4)
| (apu.pulse1.sweep_negative << 3) | apu.pulse1.sweep_shift_count;
case 0x4002:
return apu.pulse1.timer_low;
case 0x4003:
return (apu.pulse1.length_counter_load << 3) | apu.pulse1.timer_high;
/* pulse2 */
case 0x4004:
return (apu.pulse2.duty << 6) | (apu.pulse2.envelope << 5)
| (apu.pulse2.const_vol << 4) | apu.pulse2.envelope_vol;
case 0x4005:
return (apu.pulse1.sweep_enable << 7) | (apu.pulse1.sweep_period << 4)
| (apu.pulse1.sweep_negative << 3) | apu.pulse1.sweep_shift_count;
case 0x4006:
return apu.pulse1.timer_low;
case 0x4007:
return (apu.pulse1.length_counter_load << 3) | apu.pulse1.timer_high;
/* status */
case 0x4015:
return (apu.status.dmc_int << 7) | (apu.status.frame_int << 6)
| (apu.status.dmc_active << 4) | (apu.status.lc_noise << 3)
| (apu.status.lc_triangle << 2) | (apu.status.lc_pulse2 << 1)
| apu.status.lc_pulse1;
default:
fprintf(stderr, "Invalid APU read at $%04X!\n", addr);
return 0;
};
}
void
apu_write(uint16_t addr, uint8_t byte)
{
}

105
apu.h Normal file
View File

@ -0,0 +1,105 @@
#ifndef APU_H
#define APU_H
#include <stdint.h>
struct pulse {
/* $4000/$4004 */
uint8_t duty : 2;
uint8_t envelope : 1;
uint8_t const_vol : 1;
uint8_t envelope_vol : 4;
/* $4001/$4005 */
uint8_t sweep_enable : 1;
uint8_t sweep_period : 3;
uint8_t sweep_negative : 1;
uint8_t sweep_shift_count : 3;
/* $4002/$4006 */
uint8_t timer_low;
/* $4003/$4007 */
uint8_t length_counter_load : 5;
uint8_t timer_high : 3;
};
struct triangle {
/* $4008 */
uint8_t counter_disable : 1;
uint8_t counter_reload : 7;
/* $400A */
uint8_t timer_low;
/* $400B */
uint8_t counter_load : 5;
uint8_t timer_high : 3;
};
struct noise {
/* $400C */
uint8_t padding1 : 2;
uint8_t loop_envelope : 1;
uint8_t constant_volume : 1;
uint8_t envelope_volume : 4;
/* $400E */
uint8_t loop_noise : 1;
uint8_t padding2 : 3;
uint8_t noise_period : 4;
/* $400F */
uint8_t length_counter_load : 5;
uint8_t padding3 : 3;
};
struct dmc {
/* $4010 */
uint8_t irq_enable : 1;
uint8_t loop : 1;
uint8_t padding1 : 2;
uint8_t frequency : 4;
/* $4011 */
uint8_t padding2 : 1;
uint8_t load_counter : 7;
/* $4012 */
uint8_t sample_addr;
/* $4013 */
uint8_t sample_length;
};
struct apu {
/* $4000-$4013 (write) */
struct pulse pulse1;
struct pulse pulse2;
struct triangle triangle;
struct noise noise;
struct dmc dmc;
/* $4015 (write) */
struct control {
uint8_t padding : 3;
uint8_t dmc_enable : 1;
uint8_t noise_enable : 1;
uint8_t triangle_enable : 1;
uint8_t pulse2_enable : 1;
uint8_t pulse1_enable : 1;
} control;
/* $4015 (read) */
struct status {
uint8_t dmc_int : 1;
uint8_t frame_int : 1;
uint8_t padding : 1;
uint8_t dmc_active : 1;
uint8_t lc_noise : 1;
uint8_t lc_triangle : 1;
uint8_t lc_pulse2 : 1;
uint8_t lc_pulse1 : 1;
} status;
/* $4017 (write) */
struct frame_counter {
uint8_t mode : 1;
uint8_t irq_inhibit : 1;
uint8_t padding : 6;
} frame_counter;
};
extern struct apu apu;
void apu_tick(void);
uint8_t apu_read(uint16_t addr);
void apu_write(uint16_t addr, uint8_t byte);
#endif /* APU_H */

13
cpu.c
View File

@ -5,10 +5,11 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "apu.h"
#include "cpu.h" #include "cpu.h"
#include "opcodes.h" #include "opcodes.h"
#include "rom.h"
#include "ppu.h" #include "ppu.h"
#include "rom.h"
#define MAX(a, b) ((a > b) ? a : b) #define MAX(a, b) ((a > b) ? a : b)
@ -53,9 +54,10 @@ peek(uint16_t addr)
return rom.prg_rom[addr - 0x8000]; return rom.prg_rom[addr - 0x8000];
else else
fprintf(stderr, "PRG ROG size is not 0x4000 nor 0x8000\n"), exit(1); fprintf(stderr, "PRG ROG size is not 0x4000 nor 0x8000\n"), exit(1);
} else { } else if ((addr >= 0x4000 && addr <= 0x4013) || addr == 0x4015 || addr == 0x4017)
return apu_read(addr);
else
return memory[addr]; return memory[addr];
}
} }
static uint16_t static uint16_t
@ -68,6 +70,11 @@ peek16(uint16_t addr)
static void static void
memwrite(uint16_t addr, uint8_t byte) memwrite(uint16_t addr, uint8_t byte)
{ {
if (addr >= 0x4000 && addr <= 0x4017) {
apu_write(addr, byte);
return;
}
MEMORY_MIRROR(addr); MEMORY_MIRROR(addr);
memory[addr] = byte; memory[addr] = byte;