summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--apu.c55
-rw-r--r--apu.h105
-rw-r--r--cpu.c13
4 files changed, 171 insertions, 4 deletions
diff --git a/Makefile b/Makefile
index e0a80f1..c6481cf 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
CFLAGS = -O2 -Wall -Wextra -pedantic -Wno-unused-parameter
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
./nes ${HOME}/src/other/nes-test-roms/other/nestest.nes
diff --git a/apu.c b/apu.c
new file mode 100644
index 0000000..3c0393c
--- /dev/null
+++ b/apu.c
@@ -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)
+{
+}
diff --git a/apu.h b/apu.h
new file mode 100644
index 0000000..4c39a82
--- /dev/null
+++ b/apu.h
@@ -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 */
diff --git a/cpu.c b/cpu.c
index 509f7a8..97ece60 100644
--- a/cpu.c
+++ b/cpu.c
@@ -5,10 +5,11 @@
#include <stdlib.h>
#include <string.h>
+#include "apu.h"
#include "cpu.h"
#include "opcodes.h"
-#include "rom.h"
#include "ppu.h"
+#include "rom.h"
#define MAX(a, b) ((a > b) ? a : b)
@@ -53,9 +54,10 @@ peek(uint16_t addr)
return rom.prg_rom[addr - 0x8000];
else
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];
- }
}
static uint16_t
@@ -68,6 +70,11 @@ peek16(uint16_t addr)
static void
memwrite(uint16_t addr, uint8_t byte)
{
+ if (addr >= 0x4000 && addr <= 0x4017) {
+ apu_write(addr, byte);
+ return;
+ }
+
MEMORY_MIRROR(addr);
memory[addr] = byte;