add preliminary apu register support
This commit is contained in:
parent
c0679b404d
commit
279478f16f
2
Makefile
2
Makefile
@ -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
55
apu.c
Normal 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
105
apu.h
Normal 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
13
cpu.c
@ -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,10 +54,11 @@ 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
|
||||||
peek16(uint16_t addr)
|
peek16(uint16_t addr)
|
||||||
@ -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;
|
||||||
|
Loading…
Reference in New Issue
Block a user