diff --git a/Machines/Acorn/Archimedes/MemoryController.hpp b/Machines/Acorn/Archimedes/MemoryController.hpp index ff200b8f5..28c8cc590 100644 --- a/Machines/Acorn/Archimedes/MemoryController.hpp +++ b/Machines/Acorn/Archimedes/MemoryController.hpp @@ -10,6 +10,7 @@ #include "InputOutputController.hpp" #include "Video.hpp" +#include "Sound.hpp" #include "../../../InstructionSets/ARM/Registers.hpp" #include "../../../Outputs/Log.hpp" @@ -30,7 +31,8 @@ static_assert(BitMask<15, 14>::value == 49152); /// Models the MEMC, making this the Archimedes bus. Owns various other chips on the bus as a result. template struct MemoryController { - MemoryController(InterruptObserverT &delegate) : ioc_(delegate) {} + MemoryController(InterruptObserverT &observer) : + ioc_(observer), vidc_(observer, ioc_.sound()) {} int interrupt_mask() const { return ioc_.interrupt_mask(); @@ -251,7 +253,7 @@ struct MemoryController { std::array ram_{}; std::array rom_; InputOutputController ioc_; - Video vidc_; + Video>> vidc_; template IntT &physical_ram(uint32_t address) { diff --git a/Machines/Acorn/Archimedes/Sound.hpp b/Machines/Acorn/Archimedes/Sound.hpp index aad9bd1f0..7241c2d59 100644 --- a/Machines/Acorn/Archimedes/Sound.hpp +++ b/Machines/Acorn/Archimedes/Sound.hpp @@ -8,8 +8,11 @@ #pragma once +#include + namespace Archimedes { +/// Models the Archimedes sound output; in a real machine this is a joint efort between the VIDC and the MEMC. template struct Sound { Sound(InterruptObserverT &observer) : observer_(observer) {} @@ -34,11 +37,23 @@ struct Sound { halted_ = false; } + void set_frequency(uint8_t frequency) { + divider_ = reload_ = frequency; + } + + void set_stereo_image([[maybe_unused]] uint8_t channel, [[maybe_unused]] uint8_t value) { + // TODO. + } + void tick() { if(halted_) { return; } + --divider_; + if(divider_) return; + divider_ = reload_; + current_.start += 16; if(current_.start == current_.end) { if(next_buffer_valid_) { @@ -50,6 +65,8 @@ struct Sound { } private: + uint8_t divider_ = 0, reload_ = 0; + void set_buffer_valid(bool valid) { next_buffer_valid_ = valid; observer_.update_sound_interrupt(); diff --git a/Machines/Acorn/Archimedes/Video.hpp b/Machines/Acorn/Archimedes/Video.hpp index 3a69d0c03..1fd829e63 100644 --- a/Machines/Acorn/Archimedes/Video.hpp +++ b/Machines/Acorn/Archimedes/Video.hpp @@ -14,7 +14,11 @@ namespace Archimedes { +template struct Video { + Video(InterruptObserverT &observer, SoundT &sound) : + observer_(observer), sound_(sound) {} + void write(uint32_t value) { const auto target = (value >> 24) & 0xfc; @@ -34,11 +38,6 @@ struct Video { logger.error().append("TODO: Cursor colour %d to %03x", (target - 0x44) >> 2, value & 0x1fff); break; - case 0x60: case 0x64: case 0x68: case 0x6c: - case 0x70: case 0x74: case 0x78: case 0x7c: - logger.error().append("TODO: Stereo image register %d to %03x", (target - 0x60) >> 2, value & 0x7); - break; - case 0x80: logger.error().append("TODO: Video horizontal period: %d", (value >> 14) & 0x3ff); break; @@ -89,14 +88,24 @@ struct Video { logger.error().append("TODO: Video vertical cursor end: %d", (value >> 14) & 0x3ff); break; - case 0xc0: - logger.error().append("TODO: Sound frequency: %d", value & 0x7f); - break; - case 0xe0: logger.error().append("TODO: video control: %08x", value); break; + // + // Sound parameters. + // + case 0x60: case 0x64: case 0x68: case 0x6c: + case 0x70: case 0x74: case 0x78: case 0x7c: { + const uint8_t channel = ((value >> 26) + 7) & 7; + sound_.set_stereo_image(channel, value & 7); + } break; + + case 0xc0: + sound_.set_frequency(value & 0x7f); + break; + + default: logger.error().append("TODO: unrecognised VIDC write of %08x", value); break; @@ -105,6 +114,8 @@ struct Video { private: Log::Logger logger; + InterruptObserverT &observer_; + SoundT &sound_; }; }