#ifndef APU_H #define APU_H #include 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 */