// // BBCMicro.cpp // Clock Signal // // Created by Thomas Harte on 14/09/2025. // Copyright © 2025 Thomas Harte. All rights reserved. // #include "BBCMicro.hpp" #include "Machines/MachineTypes.hpp" #include "Processors/6502/6502.hpp" #include "Analyser/Static/Acorn/Target.hpp" #include "Outputs/Log.hpp" #include #include #include #include namespace BBCMicro { class ConcreteMachine: public Machine, public MachineTypes::ScanProducer, public MachineTypes::TimedMachine { public: ConcreteMachine( const Analyser::Static::Acorn::BBCMicroTarget &target, const ROMMachine::ROMFetcher &rom_fetcher ) : m6502_(*this) { set_clock_rate(2'000'000); // Grab ROMs. using Request = ::ROM::Request; using Name = ::ROM::Name; const auto request = Request(Name::AcornBASICII) && Request(Name::BBCMicroMOS12); auto roms = rom_fetcher(request); if(!request.validate(roms)) { throw ROMMachine::Error::MissingROMs; } const auto os_data = roms.find(Name::BBCMicroMOS12)->second; std::copy(os_data.begin(), os_data.end(), os_.begin()); install_sideways(15, roms.find(Name::AcornBASICII)->second, false); // Setup fixed parts of memory map. page(0, &ram_[0], true); page(1, &ram_[1], true); page_sideways(15); page(3, os_.data(), true); (void)target; } // MARK: - 6502 bus. Cycles perform_bus_operation( const CPU::MOS6502::BusOperation operation, const uint16_t address, uint8_t *const value ) { if(address >= 0xfc00 && address < 0xff00) { Logger::error().append("Unhandled IO access at %04x", address); return Cycles(1); } // ROM or RAM access. if(is_read(operation)) { *value = memory_[address >> 14][address]; } else { if(memory_write_masks_[address >> 14]) { memory_[address >> 14][address] = *value; } } return Cycles(1); } private: using Logger = Log::Logger; // MARK: - ScanProducer. void set_scan_target(Outputs::Display::ScanTarget *) override {} Outputs::Display::ScanStatus get_scan_status() const override { return Outputs::Display::ScanStatus{}; } // MARK: - TimedMachine. void run_for(const Cycles cycles) override { m6502_.run_for(cycles); } // MARK: - Memory. std::array ram_; using ROM = std::array; ROM os_; std::array roms_; std::bitset<16> rom_inserted_; std::bitset<16> rom_write_masks_; uint8_t *memory_[4]; std::bitset<4> memory_write_masks_; bool sideways_read_mask_ = false; void page(const size_t slot, uint8_t *const source, bool is_writeable) { memory_[slot] = source - (slot * 16384); memory_write_masks_[slot] = is_writeable; } void page_sideways(const size_t source) { sideways_read_mask_ = rom_inserted_[source]; page(2, roms_[source].data(), rom_write_masks_[source]); } void install_sideways(const size_t slot, const std::vector &source, bool is_writeable) { rom_write_masks_[slot] = is_writeable; assert(source.size() == roms_[slot].size()); std::copy(source.begin(), source.end(), roms_[slot].begin()); } // MARK: - Components. CPU::MOS6502::Processor m6502_; }; } using namespace BBCMicro; std::unique_ptr Machine::BBCMicro( const Analyser::Static::Target *target, const ROMMachine::ROMFetcher &rom_fetcher ) { using Target = Analyser::Static::Acorn::BBCMicroTarget; const Target *const acorn_target = dynamic_cast(target); return std::make_unique(*acorn_target, rom_fetcher); }