summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorvin <git@vineetk.net>2024-08-31 22:24:33 -0400
committervin <git@vineetk.net>2024-09-01 01:49:37 -0400
commit279478f16f8ea4fcc3c8765ff964954368664106 (patch)
treea3c3c1bb28d26f9040a3afec7f519c92fc7ac5a0
parentc0679b404d3bd9c20133a1868113f200eae2cf9f (diff)
add preliminary apu register support
-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 @@
1CFLAGS = -O2 -Wall -Wextra -pedantic -Wno-unused-parameter 1CFLAGS = -O2 -Wall -Wextra -pedantic -Wno-unused-parameter
2 2
3nes: 3nes:
4 ${CC} ${CFLAGS} -o nes cpu.c rom.c ppu.c 4 ${CC} ${CFLAGS} -o nes cpu.c rom.c ppu.c apu.c
5 5
6test: nes 6test: nes
7 ./nes ${HOME}/src/other/nes-test-roms/other/nestest.nes 7 ./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 @@
1#include <stdio.h>
2#include <string.h>
3
4#include "apu.h"
5
6struct apu apu = {0};
7
8void
9apu_init(void)
10{
11 memset(&apu, 0, sizeof(apu));
12}
13
14uint8_t
15apu_read(uint16_t addr)
16{
17 switch (addr) {
18 /* pulse1 */
19 case 0x4000:
20 return (apu.pulse1.duty << 6) | (apu.pulse1.envelope << 5)
21 | (apu.pulse1.const_vol << 4) | apu.pulse1.envelope_vol;
22 case 0x4001:
23 return (apu.pulse1.sweep_enable << 7) | (apu.pulse1.sweep_period << 4)
24 | (apu.pulse1.sweep_negative << 3) | apu.pulse1.sweep_shift_count;
25 case 0x4002:
26 return apu.pulse1.timer_low;
27 case 0x4003:
28 return (apu.pulse1.length_counter_load << 3) | apu.pulse1.timer_high;
29 /* pulse2 */
30 case 0x4004:
31 return (apu.pulse2.duty << 6) | (apu.pulse2.envelope << 5)
32 | (apu.pulse2.const_vol << 4) | apu.pulse2.envelope_vol;
33 case 0x4005:
34 return (apu.pulse1.sweep_enable << 7) | (apu.pulse1.sweep_period << 4)
35 | (apu.pulse1.sweep_negative << 3) | apu.pulse1.sweep_shift_count;
36 case 0x4006:
37 return apu.pulse1.timer_low;
38 case 0x4007:
39 return (apu.pulse1.length_counter_load << 3) | apu.pulse1.timer_high;
40 /* status */
41 case 0x4015:
42 return (apu.status.dmc_int << 7) | (apu.status.frame_int << 6)
43 | (apu.status.dmc_active << 4) | (apu.status.lc_noise << 3)
44 | (apu.status.lc_triangle << 2) | (apu.status.lc_pulse2 << 1)
45 | apu.status.lc_pulse1;
46 default:
47 fprintf(stderr, "Invalid APU read at $%04X!\n", addr);
48 return 0;
49 };
50}
51
52void
53apu_write(uint16_t addr, uint8_t byte)
54{
55}
diff --git a/apu.h b/apu.h
new file mode 100644
index 0000000..4c39a82
--- /dev/null
+++ b/apu.h
@@ -0,0 +1,105 @@
1#ifndef APU_H
2#define APU_H
3
4#include <stdint.h>
5
6struct pulse {
7 /* $4000/$4004 */
8 uint8_t duty : 2;
9 uint8_t envelope : 1;
10 uint8_t const_vol : 1;
11 uint8_t envelope_vol : 4;
12 /* $4001/$4005 */
13 uint8_t sweep_enable : 1;
14 uint8_t sweep_period : 3;
15 uint8_t sweep_negative : 1;
16 uint8_t sweep_shift_count : 3;
17 /* $4002/$4006 */
18 uint8_t timer_low;
19 /* $4003/$4007 */
20 uint8_t length_counter_load : 5;
21 uint8_t timer_high : 3;
22};
23
24struct triangle {
25 /* $4008 */
26 uint8_t counter_disable : 1;
27 uint8_t counter_reload : 7;
28 /* $400A */
29 uint8_t timer_low;
30 /* $400B */
31 uint8_t counter_load : 5;
32 uint8_t timer_high : 3;
33};
34
35struct noise {
36 /* $400C */
37 uint8_t padding1 : 2;
38 uint8_t loop_envelope : 1;
39 uint8_t constant_volume : 1;
40 uint8_t envelope_volume : 4;
41 /* $400E */
42 uint8_t loop_noise : 1;
43 uint8_t padding2 : 3;
44 uint8_t noise_period : 4;
45 /* $400F */
46 uint8_t length_counter_load : 5;
47 uint8_t padding3 : 3;
48};
49
50struct dmc {
51 /* $4010 */
52 uint8_t irq_enable : 1;
53 uint8_t loop : 1;
54 uint8_t padding1 : 2;
55 uint8_t frequency : 4;
56 /* $4011 */
57 uint8_t padding2 : 1;
58 uint8_t load_counter : 7;
59 /* $4012 */
60 uint8_t sample_addr;
61 /* $4013 */
62 uint8_t sample_length;
63};
64
65struct apu {
66 /* $4000-$4013 (write) */
67 struct pulse pulse1;
68 struct pulse pulse2;
69 struct triangle triangle;
70 struct noise noise;
71 struct dmc dmc;
72 /* $4015 (write) */
73 struct control {
74 uint8_t padding : 3;
75 uint8_t dmc_enable : 1;
76 uint8_t noise_enable : 1;
77 uint8_t triangle_enable : 1;
78 uint8_t pulse2_enable : 1;
79 uint8_t pulse1_enable : 1;
80 } control;
81 /* $4015 (read) */
82 struct status {
83 uint8_t dmc_int : 1;
84 uint8_t frame_int : 1;
85 uint8_t padding : 1;
86 uint8_t dmc_active : 1;
87 uint8_t lc_noise : 1;
88 uint8_t lc_triangle : 1;
89 uint8_t lc_pulse2 : 1;
90 uint8_t lc_pulse1 : 1;
91 } status;
92 /* $4017 (write) */
93 struct frame_counter {
94 uint8_t mode : 1;
95 uint8_t irq_inhibit : 1;
96 uint8_t padding : 6;
97 } frame_counter;
98};
99extern struct apu apu;
100
101void apu_tick(void);
102uint8_t apu_read(uint16_t addr);
103void apu_write(uint16_t addr, uint8_t byte);
104
105#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 @@
5#include <stdlib.h> 5#include <stdlib.h>
6#include <string.h> 6#include <string.h>
7 7
8#include "apu.h"
8#include "cpu.h" 9#include "cpu.h"
9#include "opcodes.h" 10#include "opcodes.h"
10#include "rom.h"
11#include "ppu.h" 11#include "ppu.h"
12#include "rom.h"
12 13
13#define MAX(a, b) ((a > b) ? a : b) 14#define MAX(a, b) ((a > b) ? a : b)
14 15
@@ -53,9 +54,10 @@ peek(uint16_t addr)
53 return rom.prg_rom[addr - 0x8000]; 54 return rom.prg_rom[addr - 0x8000];
54 else 55 else
55 fprintf(stderr, "PRG ROG size is not 0x4000 nor 0x8000\n"), exit(1); 56 fprintf(stderr, "PRG ROG size is not 0x4000 nor 0x8000\n"), exit(1);
56 } else { 57 } else if ((addr >= 0x4000 && addr <= 0x4013) || addr == 0x4015 || addr == 0x4017)
58 return apu_read(addr);
59 else
57 return memory[addr]; 60 return memory[addr];
58 }
59} 61}
60 62
61static uint16_t 63static uint16_t
@@ -68,6 +70,11 @@ peek16(uint16_t addr)
68static void 70static void
69memwrite(uint16_t addr, uint8_t byte) 71memwrite(uint16_t addr, uint8_t byte)
70{ 72{
73 if (addr >= 0x4000 && addr <= 0x4017) {
74 apu_write(addr, byte);
75 return;
76 }
77
71 MEMORY_MIRROR(addr); 78 MEMORY_MIRROR(addr);
72 79
73 memory[addr] = byte; 80 memory[addr] = byte;