diff --git a/Machines/Commodore/Plus4/Plus4.cpp b/Machines/Commodore/Plus4/Plus4.cpp index 5d0ea1ddb..3c5a3b59a 100644 --- a/Machines/Commodore/Plus4/Plus4.cpp +++ b/Machines/Commodore/Plus4/Plus4.cpp @@ -19,6 +19,8 @@ #include "../../../Analyser/Static/Commodore/Target.hpp" #include "../../../Storage/Tape/Tape.hpp" +#include "../SerialBus.hpp" +#include "../1540/C1540.hpp" using namespace Commodore::Plus4; @@ -100,6 +102,20 @@ private: Interrupts &interrupts_; }; +class SerialPort: public Commodore::Serial::Port { +public: + void set_input(Commodore::Serial::Line line, Commodore::Serial::LineLevel value) override { + levels_[size_t(line)] = value; + } + + Commodore::Serial::LineLevel level(Commodore::Serial::Line line) const { + return levels_[size_t(line)]; + } + +private: + Commodore::Serial::LineLevel levels_[5]; +}; + class ConcreteMachine: public BusController, public CPU::MOS6502::BusHandler, @@ -118,12 +134,17 @@ public: const auto clock = clock_rate(false); media_divider_ = Cycles(clock); set_clock_rate(clock); - tape_player_ = std::make_unique(clock); + + // TODO: decide whether to attach a 1541 for real. + const bool has_c1541 = true; const auto kernel = ROM::Name::Plus4KernelPALv5; const auto basic = ROM::Name::Plus4BASIC; + ROM::Request request = ROM::Request(basic) && ROM::Request(kernel); + if(has_c1541) { + request = request && Commodore::C1540::Machine::rom_request(Commodore::C1540::Personality::C1541); + } - const ROM::Request request = ROM::Request(basic) && ROM::Request(kernel); auto roms = rom_fetcher(request); if(!request.validate(roms)) { throw ROMMachine::Error::MissingROMs; @@ -138,6 +159,14 @@ public: video_map_.page(ram_.data()); + if(has_c1541) { + c1541_ = std::make_unique(Commodore::C1540::Personality::C1541, roms); + c1541_->set_serial_bus(serial_bus_); + serial_port_.set_bus(serial_bus_); + } + + tape_player_ = std::make_unique(clock); + insert_media(target.media); printf("Loading command is: %s\n", target.loading_command.c_str()); } @@ -159,6 +188,11 @@ public: video_.run_for(length); tape_player_->run_for(length); + if(c1541_) { + c1541_cycles_ += length; + c1541_->run_for(c1541_cycles_.divide(media_divider_)); + } + if(operation == CPU::MOS6502::BusOperation::Ready) { return length; } @@ -179,9 +213,11 @@ public: if(isReadOperation(operation)) { if(!address) { *value = io_direction_; -// printf("Read data direction: %02x\n", *value); } else { - const uint8_t all_inputs = (tape_player_->input() ? 0x00 : 0x10) | 0xe0; + const uint8_t all_inputs = + (tape_player_->input() ? 0x00 : 0x10) | + (serial_port_.level(Commodore::Serial::Line::Data) ? 0x80 : 0x00) | + (serial_port_.level(Commodore::Serial::Line::Clock) ? 0x40 : 0x00); *value = (io_direction_ & io_output_) | ((~io_direction_) & all_inputs); @@ -190,13 +226,18 @@ public: } else { if(!address) { io_direction_ = *value; -// printf("Set data direction: %02x\n", *value); } else { io_output_ = *value; - printf("[%04x] Out: %02x\n", m6502_.value_of(CPU::MOS6502::Register::ProgramCounter), *value); -// tape_player_->set_motor_control(*value & 0x08); - tape_player_->set_motor_control(!(*value & 0x08)); } + + const auto output = io_output_ & ~io_direction_; + tape_player_->set_motor_control(!(output & 0x08)); + serial_port_.set_output( + Commodore::Serial::Line::Data, Commodore::Serial::LineLevel(~output & 0x01)); + serial_port_.set_output( + Commodore::Serial::Line::Clock, Commodore::Serial::LineLevel(~output & 0x02)); + serial_port_.set_output( + Commodore::Serial::Line::Attention, Commodore::Serial::LineLevel(~output & 0x04)); } // printf("%04x: %02x %c\n", address, *value, isReadOperation(operation) ? 'r' : 'w'); @@ -372,6 +413,10 @@ private: tape_player_->set_tape(media.tapes[0]); } + if(!media.disks.empty() && c1541_) { + c1541_->set_disk(media.disks[0]); + } + return true; } @@ -404,12 +449,16 @@ private: std::array key_states_{}; uint8_t keyboard_latch_ = 0xff; - Cycles media_divider_; + Cycles media_divider_, c1541_cycles_; + std::unique_ptr c1541_; + Commodore::Serial::Bus serial_bus_; + SerialPort serial_port_; + std::unique_ptr tape_player_; uint8_t io_direction_ = 0x00, io_output_ = 0x00; }; - } + std::unique_ptr Machine::Plus4( const Analyser::Static::Target *target, const ROMMachine::ROMFetcher &rom_fetcher diff --git a/Machines/Commodore/SerialBus.hpp b/Machines/Commodore/SerialBus.hpp index c8bdfd4e4..40be0f4b2 100644 --- a/Machines/Commodore/SerialBus.hpp +++ b/Machines/Commodore/SerialBus.hpp @@ -56,13 +56,13 @@ public: /*! Adds the supplied port to the bus. */ - void add_port(Port &port); + void add_port(Port &); /*! Communicates to the bus that one of its attached port has changed its output level for the given line. The bus will therefore recalculate bus state and propagate as necessary. */ - void set_line_output_did_change(Line line); + void set_line_output_did_change(Line); private: LineLevel line_levels_[5]; @@ -97,7 +97,7 @@ public: /*! Gets the previously set level of an output line. */ - LineLevel get_output(Line line) { + LineLevel get_output(Line line) const { return line_levels_[size_t(line)]; } diff --git a/Machines/Commodore/Vic-20/Vic20.cpp b/Machines/Commodore/Vic-20/Vic20.cpp index 1a6982345..42f6a13f2 100644 --- a/Machines/Commodore/Vic-20/Vic20.cpp +++ b/Machines/Commodore/Vic-20/Vic20.cpp @@ -352,7 +352,7 @@ public: if(target.has_c1540) { // construct the 1540 - c1540_ = std::make_unique<::Commodore::C1540::Machine>(Commodore::C1540::Personality::C1540, roms); + c1540_ = std::make_unique(C1540::Personality::C1540, roms); // attach it to the serial bus c1540_->set_serial_bus(serial_bus_);