From 08f98aa32f7788253bd47bf85388773c2c9518b3 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Fri, 6 Dec 2024 13:52:42 -0500 Subject: [PATCH] Decrease indentation. --- Machines/Commodore/Vic-20/Vic20.cpp | 1120 ++++++++++++++------------- Machines/Commodore/Vic-20/Vic20.hpp | 34 +- 2 files changed, 578 insertions(+), 576 deletions(-) diff --git a/Machines/Commodore/Vic-20/Vic20.cpp b/Machines/Commodore/Vic-20/Vic20.cpp index dfc0462c4..85d33fbcd 100644 --- a/Machines/Commodore/Vic-20/Vic20.cpp +++ b/Machines/Commodore/Vic-20/Vic20.cpp @@ -63,67 +63,67 @@ enum JoystickInput { state from its serial port. Most of the joystick input is also exposed here. */ class UserPortVIA: public MOS::MOS6522::IRQDelegatePortHandler { - public: - UserPortVIA() : port_a_(0xbf) {} +public: + UserPortVIA() : port_a_(0xbf) {} - /// Reports the current input to the 6522 port @c port. - uint8_t get_port_input(MOS::MOS6522::Port port) { - // Port A provides information about the presence or absence of a tape, and parts of - // the joystick and serial port state, both of which have been statefully collected - // into port_a_. - if(!port) { - return port_a_ | (tape_->has_tape() ? 0x00 : 0x40); - } - return 0xff; + /// Reports the current input to the 6522 port @c port. + uint8_t get_port_input(MOS::MOS6522::Port port) { + // Port A provides information about the presence or absence of a tape, and parts of + // the joystick and serial port state, both of which have been statefully collected + // into port_a_. + if(!port) { + return port_a_ | (tape_->has_tape() ? 0x00 : 0x40); } + return 0xff; + } - /// Receives announcements of control line output change from the 6522. - void set_control_line_output(MOS::MOS6522::Port port, MOS::MOS6522::Line line, bool value) { - // The CA2 output is used to control the tape motor. - if(port == MOS::MOS6522::Port::A && line == MOS::MOS6522::Line::Two) { - tape_->set_motor_control(!value); - } + /// Receives announcements of control line output change from the 6522. + void set_control_line_output(MOS::MOS6522::Port port, MOS::MOS6522::Line line, bool value) { + // The CA2 output is used to control the tape motor. + if(port == MOS::MOS6522::Port::A && line == MOS::MOS6522::Line::Two) { + tape_->set_motor_control(!value); } + } - /// Receives announcements of changes in the serial bus connected to the serial port and propagates them into Port A. - void set_serial_line_state(::Commodore::Serial::Line line, bool value) { - switch(line) { - default: break; - case ::Commodore::Serial::Line::Data: port_a_ = (port_a_ & ~0x02) | (value ? 0x02 : 0x00); break; - case ::Commodore::Serial::Line::Clock: port_a_ = (port_a_ & ~0x01) | (value ? 0x01 : 0x00); break; - } + /// Receives announcements of changes in the serial bus connected to the serial port and propagates them into Port A. + void set_serial_line_state(::Commodore::Serial::Line line, bool value) { + switch(line) { + default: break; + case ::Commodore::Serial::Line::Data: port_a_ = (port_a_ & ~0x02) | (value ? 0x02 : 0x00); break; + case ::Commodore::Serial::Line::Clock: port_a_ = (port_a_ & ~0x01) | (value ? 0x01 : 0x00); break; } + } - /// Allows the current joystick input to be set. - void set_joystick_state(JoystickInput input, bool value) { - if(input != JoystickInput::Right) { - port_a_ = (port_a_ & ~input) | (value ? 0 : input); - } + /// Allows the current joystick input to be set. + void set_joystick_state(JoystickInput input, bool value) { + if(input != JoystickInput::Right) { + port_a_ = (port_a_ & ~input) | (value ? 0 : input); } + } - /// Receives announcements from the 6522 of user-port output, which might affect what's currently being presented onto the serial bus. - void set_port_output(MOS::MOS6522::Port port, uint8_t value, uint8_t) { - // Line 7 of port A is inverted and output as serial ATN. - if(!port) { - std::shared_ptr<::Commodore::Serial::Port> serialPort = serial_port_.lock(); - if(serialPort) serialPort->set_output(::Commodore::Serial::Line::Attention, (::Commodore::Serial::LineLevel)!(value&0x80)); - } + /// Receives announcements from the 6522 of user-port output, which might affect what's currently being presented onto the serial bus. + void set_port_output(MOS::MOS6522::Port port, uint8_t value, uint8_t) { + // Line 7 of port A is inverted and output as serial ATN. + if(!port) { + std::shared_ptr<::Commodore::Serial::Port> serialPort = serial_port_.lock(); + if(serialPort) serialPort->set_output(::Commodore::Serial::Line::Attention, (::Commodore::Serial::LineLevel)!(value&0x80)); } + } - /// Sets @serial_port as this VIA's connection to the serial bus. - void set_serial_port(std::shared_ptr<::Commodore::Serial::Port> serial_port) { - serial_port_ = serial_port; - } + /// Sets @serial_port as this VIA's connection to the serial bus. + void set_serial_port(std::shared_ptr<::Commodore::Serial::Port> serial_port) { + serial_port_ = serial_port; + } - /// Sets @tape as the tape player connected to this VIA. - void set_tape(std::shared_ptr tape) { - tape_ = tape; - } + /// Sets @tape as the tape player connected to this VIA. + void set_tape(std::shared_ptr tape) { + tape_ = tape; + } - private: - uint8_t port_a_; - std::weak_ptr<::Commodore::Serial::Port> serial_port_; - std::shared_ptr tape_; +private: + uint8_t port_a_; + std::weak_ptr<::Commodore::Serial::Port> serial_port_; + std::shared_ptr tape_; }; /*! @@ -131,146 +131,145 @@ class UserPortVIA: public MOS::MOS6522::IRQDelegatePortHandler { and for the small portion of joystick input not connected to the user-port VIA. */ class KeyboardVIA: public MOS::MOS6522::IRQDelegatePortHandler { - public: - KeyboardVIA() : port_b_(0xff) { - clear_all_keys(); - } +public: + KeyboardVIA() : port_b_(0xff) { + clear_all_keys(); + } - /// Sets whether @c key @c is_pressed. - void set_key_state(uint16_t key, bool is_pressed) { - if(is_pressed) - columns_[key & 7] &= ~(key >> 3); - else - columns_[key & 7] |= (key >> 3); - } + /// Sets whether @c key @c is_pressed. + void set_key_state(uint16_t key, bool is_pressed) { + if(is_pressed) + columns_[key & 7] &= ~(key >> 3); + else + columns_[key & 7] |= (key >> 3); + } - /// Sets all keys as unpressed. - void clear_all_keys() { - memset(columns_, 0xff, sizeof(columns_)); - } + /// Sets all keys as unpressed. + void clear_all_keys() { + memset(columns_, 0xff, sizeof(columns_)); + } - /// Called by the 6522 to get input. Reads the keyboard on Port A, returns a small amount of joystick state on Port B. - uint8_t get_port_input(MOS::MOS6522::Port port) { - if(!port) { - uint8_t result = 0xff; - for(int c = 0; c < 8; c++) { - if(!(activation_mask_&(1 << c))) - result &= columns_[c]; - } - return result; + /// Called by the 6522 to get input. Reads the keyboard on Port A, returns a small amount of joystick state on Port B. + uint8_t get_port_input(MOS::MOS6522::Port port) { + if(!port) { + uint8_t result = 0xff; + for(int c = 0; c < 8; c++) { + if(!(activation_mask_&(1 << c))) + result &= columns_[c]; } - - return port_b_; + return result; } - /// Called by the 6522 to set output. The value of Port B selects which part of the keyboard to read. - void set_port_output(MOS::MOS6522::Port port, uint8_t value, uint8_t mask) { - if(port) activation_mask_ = (value & mask) | (~mask); - } + return port_b_; + } - /// Called by the 6522 to set control line output. Which affects the serial port. - void set_control_line_output(MOS::MOS6522::Port port, MOS::MOS6522::Line line, bool value) { - if(line == MOS::MOS6522::Line::Two) { - std::shared_ptr<::Commodore::Serial::Port> serialPort = serial_port_.lock(); - if(serialPort) { - // CB2 is inverted to become serial data; CA2 is inverted to become serial clock - if(port == MOS::MOS6522::Port::A) - serialPort->set_output(::Commodore::Serial::Line::Clock, (::Commodore::Serial::LineLevel)!value); - else - serialPort->set_output(::Commodore::Serial::Line::Data, (::Commodore::Serial::LineLevel)!value); - } + /// Called by the 6522 to set output. The value of Port B selects which part of the keyboard to read. + void set_port_output(MOS::MOS6522::Port port, uint8_t value, uint8_t mask) { + if(port) activation_mask_ = (value & mask) | (~mask); + } + + /// Called by the 6522 to set control line output. Which affects the serial port. + void set_control_line_output(MOS::MOS6522::Port port, MOS::MOS6522::Line line, bool value) { + if(line == MOS::MOS6522::Line::Two) { + std::shared_ptr<::Commodore::Serial::Port> serialPort = serial_port_.lock(); + if(serialPort) { + // CB2 is inverted to become serial data; CA2 is inverted to become serial clock + if(port == MOS::MOS6522::Port::A) + serialPort->set_output(::Commodore::Serial::Line::Clock, (::Commodore::Serial::LineLevel)!value); + else + serialPort->set_output(::Commodore::Serial::Line::Data, (::Commodore::Serial::LineLevel)!value); } } + } - /// Sets whether the joystick input @c input is pressed. - void set_joystick_state(JoystickInput input, bool value) { - if(input == JoystickInput::Right) { - port_b_ = (port_b_ & ~input) | (value ? 0 : input); - } + /// Sets whether the joystick input @c input is pressed. + void set_joystick_state(JoystickInput input, bool value) { + if(input == JoystickInput::Right) { + port_b_ = (port_b_ & ~input) | (value ? 0 : input); } + } - /// Sets the serial port to which this VIA is connected. - void set_serial_port(std::shared_ptr<::Commodore::Serial::Port> serialPort) { - serial_port_ = serialPort; - } + /// Sets the serial port to which this VIA is connected. + void set_serial_port(std::shared_ptr<::Commodore::Serial::Port> serialPort) { + serial_port_ = serialPort; + } - private: - uint8_t port_b_; - uint8_t columns_[8]; - uint8_t activation_mask_; - std::weak_ptr<::Commodore::Serial::Port> serial_port_; +private: + uint8_t port_b_; + uint8_t columns_[8]; + uint8_t activation_mask_; + std::weak_ptr<::Commodore::Serial::Port> serial_port_; }; /*! Models the Vic's serial port, providing the receipticle for input. */ class SerialPort : public ::Commodore::Serial::Port { - public: - /// Receives an input change from the base serial port class, and communicates it to the user-port VIA. - void set_input(::Commodore::Serial::Line line, ::Commodore::Serial::LineLevel level) { - std::shared_ptr userPortVIA = user_port_via_.lock(); - if(userPortVIA) userPortVIA->set_serial_line_state(line, bool(level)); - } +public: + /// Receives an input change from the base serial port class, and communicates it to the user-port VIA. + void set_input(::Commodore::Serial::Line line, ::Commodore::Serial::LineLevel level) { + std::shared_ptr userPortVIA = user_port_via_.lock(); + if(userPortVIA) userPortVIA->set_serial_line_state(line, bool(level)); + } - /// Sets the user-port VIA with which this serial port communicates. - void set_user_port_via(std::shared_ptr userPortVIA) { - user_port_via_ = userPortVIA; - } + /// Sets the user-port VIA with which this serial port communicates. + void set_user_port_via(std::shared_ptr userPortVIA) { + user_port_via_ = userPortVIA; + } - private: - std::weak_ptr user_port_via_; +private: + std::weak_ptr user_port_via_; }; /*! Provides the bus over which the Vic 6560 fetches memory in a Vic-20. */ -class Vic6560BusHandler { - public: - /// Performs a read on behalf of the 6560; in practice uses @c video_memory_map and @c colour_memory to find data. - forceinline void perform_read(uint16_t address, uint8_t *pixel_data, uint8_t *colour_data) { - *pixel_data = video_memory_map[address >> 10] ? video_memory_map[address >> 10][address & 0x3ff] : 0xff; // TODO - *colour_data = colour_memory[address & 0x03ff]; - } +struct Vic6560BusHandler { + /// Performs a read on behalf of the 6560; in practice uses @c video_memory_map and @c colour_memory to find data. + forceinline void perform_read(uint16_t address, uint8_t *pixel_data, uint8_t *colour_data) { + *pixel_data = video_memory_map[address >> 10] ? video_memory_map[address >> 10][address & 0x3ff] : 0xff; // TODO + *colour_data = colour_memory[address & 0x03ff]; + } - // It is assumed that these pointers have been filled in by the machine. - uint8_t *video_memory_map[16]{}; // Segments video memory into 1kb portions. - uint8_t *colour_memory{}; // Colour memory must be contiguous. + // It is assumed that these pointers have been filled in by the machine. + uint8_t *video_memory_map[16]{}; // Segments video memory into 1kb portions. + uint8_t *colour_memory{}; // Colour memory must be contiguous. }; /*! Interfaces a joystick to the two VIAs. */ class Joystick: public Inputs::ConcreteJoystick { - public: - Joystick(UserPortVIA &user_port_via_port_handler, KeyboardVIA &keyboard_via_port_handler) : - ConcreteJoystick({ - Input(Input::Up), - Input(Input::Down), - Input(Input::Left), - Input(Input::Right), - Input(Input::Fire) - }), - user_port_via_port_handler_(user_port_via_port_handler), - keyboard_via_port_handler_(keyboard_via_port_handler) {} +public: + Joystick(UserPortVIA &user_port_via_port_handler, KeyboardVIA &keyboard_via_port_handler) : + ConcreteJoystick({ + Input(Input::Up), + Input(Input::Down), + Input(Input::Left), + Input(Input::Right), + Input(Input::Fire) + }), + user_port_via_port_handler_(user_port_via_port_handler), + keyboard_via_port_handler_(keyboard_via_port_handler) {} - void did_set_input(const Input &digital_input, bool is_active) final { - JoystickInput mapped_input; - switch(digital_input.type) { - default: return; - case Input::Up: mapped_input = Up; break; - case Input::Down: mapped_input = Down; break; - case Input::Left: mapped_input = Left; break; - case Input::Right: mapped_input = Right; break; - case Input::Fire: mapped_input = Fire; break; - } - - user_port_via_port_handler_.set_joystick_state(mapped_input, is_active); - keyboard_via_port_handler_.set_joystick_state(mapped_input, is_active); + void did_set_input(const Input &digital_input, bool is_active) final { + JoystickInput mapped_input; + switch(digital_input.type) { + default: return; + case Input::Up: mapped_input = Up; break; + case Input::Down: mapped_input = Down; break; + case Input::Left: mapped_input = Left; break; + case Input::Right: mapped_input = Right; break; + case Input::Fire: mapped_input = Fire; break; } - private: - UserPortVIA &user_port_via_port_handler_; - KeyboardVIA &keyboard_via_port_handler_; + user_port_via_port_handler_.set_joystick_state(mapped_input, is_active); + keyboard_via_port_handler_.set_joystick_state(mapped_input, is_active); + } + +private: + UserPortVIA &user_port_via_port_handler_; + KeyboardVIA &keyboard_via_port_handler_; }; class ConcreteMachine: @@ -288,481 +287,484 @@ class ConcreteMachine: public Machine, public ClockingHint::Observer, public Activity::Source { - public: - ConcreteMachine(const Analyser::Static::Commodore::Target &target, const ROMMachine::ROMFetcher &rom_fetcher) : - m6502_(*this), - mos6560_(mos6560_bus_handler_), - user_port_via_port_handler_(new UserPortVIA), - keyboard_via_port_handler_(new KeyboardVIA), - serial_port_(new SerialPort), - serial_bus_(new ::Commodore::Serial::Bus), - user_port_via_(*user_port_via_port_handler_), - keyboard_via_(*keyboard_via_port_handler_), - tape_(new Storage::Tape::BinaryTapePlayer(1022727)) { - // communicate the tape to the user-port VIA - user_port_via_port_handler_->set_tape(tape_); +public: + ConcreteMachine(const Analyser::Static::Commodore::Target &target, const ROMMachine::ROMFetcher &rom_fetcher) : + m6502_(*this), + mos6560_(mos6560_bus_handler_), + user_port_via_port_handler_(new UserPortVIA), + keyboard_via_port_handler_(new KeyboardVIA), + serial_port_(new SerialPort), + serial_bus_(new ::Commodore::Serial::Bus), + user_port_via_(*user_port_via_port_handler_), + keyboard_via_(*keyboard_via_port_handler_), + tape_(new Storage::Tape::BinaryTapePlayer(1022727)) { + // communicate the tape to the user-port VIA + user_port_via_port_handler_->set_tape(tape_); - // wire up the serial bus and serial port - Commodore::Serial::AttachPortAndBus(serial_port_, serial_bus_); + // wire up the serial bus and serial port + Commodore::Serial::AttachPortAndBus(serial_port_, serial_bus_); - // wire up 6522s and serial port - user_port_via_port_handler_->set_serial_port(serial_port_); - keyboard_via_port_handler_->set_serial_port(serial_port_); - serial_port_->set_user_port_via(user_port_via_port_handler_); + // wire up 6522s and serial port + user_port_via_port_handler_->set_serial_port(serial_port_); + keyboard_via_port_handler_->set_serial_port(serial_port_); + serial_port_->set_user_port_via(user_port_via_port_handler_); - // wire up the 6522s, tape and machine - user_port_via_port_handler_->set_interrupt_delegate(this); - keyboard_via_port_handler_->set_interrupt_delegate(this); - tape_->set_delegate(this); - tape_->set_clocking_hint_observer(this); + // wire up the 6522s, tape and machine + user_port_via_port_handler_->set_interrupt_delegate(this); + keyboard_via_port_handler_->set_interrupt_delegate(this); + tape_->set_delegate(this); + tape_->set_clocking_hint_observer(this); - // Install a joystick. - joysticks_.emplace_back(new Joystick(*user_port_via_port_handler_, *keyboard_via_port_handler_)); + // Install a joystick. + joysticks_.emplace_back(new Joystick(*user_port_via_port_handler_, *keyboard_via_port_handler_)); - ROM::Request request(ROM::Name::Vic20BASIC); - ROM::Name kernel, character; - switch(target.region) { - default: - character = ROM::Name::Vic20EnglishCharacters; - kernel = ROM::Name::Vic20EnglishPALKernel; - break; - case Analyser::Static::Commodore::Target::Region::American: - character = ROM::Name::Vic20EnglishCharacters; - kernel = ROM::Name::Vic20EnglishNTSCKernel; - break; - case Analyser::Static::Commodore::Target::Region::Danish: - character = ROM::Name::Vic20DanishCharacters; - kernel = ROM::Name::Vic20DanishKernel; - break; - case Analyser::Static::Commodore::Target::Region::Japanese: - character = ROM::Name::Vic20JapaneseCharacters; - kernel = ROM::Name::Vic20JapaneseKernel; - break; - case Analyser::Static::Commodore::Target::Region::Swedish: - character = ROM::Name::Vic20SwedishCharacters; - kernel = ROM::Name::Vic20SwedishKernel; - break; - } + ROM::Request request(ROM::Name::Vic20BASIC); + ROM::Name kernel, character; + switch(target.region) { + default: + character = ROM::Name::Vic20EnglishCharacters; + kernel = ROM::Name::Vic20EnglishPALKernel; + break; + case Analyser::Static::Commodore::Target::Region::American: + character = ROM::Name::Vic20EnglishCharacters; + kernel = ROM::Name::Vic20EnglishNTSCKernel; + break; + case Analyser::Static::Commodore::Target::Region::Danish: + character = ROM::Name::Vic20DanishCharacters; + kernel = ROM::Name::Vic20DanishKernel; + break; + case Analyser::Static::Commodore::Target::Region::Japanese: + character = ROM::Name::Vic20JapaneseCharacters; + kernel = ROM::Name::Vic20JapaneseKernel; + break; + case Analyser::Static::Commodore::Target::Region::Swedish: + character = ROM::Name::Vic20SwedishCharacters; + kernel = ROM::Name::Vic20SwedishKernel; + break; + } - if(target.has_c1540) { - request = request && Commodore::C1540::Machine::rom_request(Commodore::C1540::Personality::C1540); - } - request = request && ROM::Request(character) && ROM::Request(kernel); + if(target.has_c1540) { + request = request && Commodore::C1540::Machine::rom_request(Commodore::C1540::Personality::C1540); + } + request = request && ROM::Request(character) && ROM::Request(kernel); - auto roms = rom_fetcher(request); - if(!request.validate(roms)) { - throw ROMMachine::Error::MissingROMs; - } + auto roms = rom_fetcher(request); + if(!request.validate(roms)) { + throw ROMMachine::Error::MissingROMs; + } - basic_rom_ = std::move(roms.find(ROM::Name::Vic20BASIC)->second); - character_rom_ = std::move(roms.find(character)->second); - kernel_rom_ = std::move(roms.find(kernel)->second); + basic_rom_ = std::move(roms.find(ROM::Name::Vic20BASIC)->second); + character_rom_ = std::move(roms.find(character)->second); + kernel_rom_ = std::move(roms.find(kernel)->second); - if(target.has_c1540) { - // construct the 1540 - c1540_ = std::make_unique<::Commodore::C1540::Machine>(Commodore::C1540::Personality::C1540, roms); + if(target.has_c1540) { + // construct the 1540 + c1540_ = std::make_unique<::Commodore::C1540::Machine>(Commodore::C1540::Personality::C1540, roms); - // attach it to the serial bus - c1540_->set_serial_bus(serial_bus_); + // attach it to the serial bus + c1540_->set_serial_bus(serial_bus_); - // give it a little warm up - c1540_->run_for(Cycles(2000000)); - } + // give it a little warm up + c1540_->run_for(Cycles(2000000)); + } - // Determine PAL/NTSC - if(target.region == Analyser::Static::Commodore::Target::Region::American || target.region == Analyser::Static::Commodore::Target::Region::Japanese) { - // NTSC - set_clock_rate(1022727); - mos6560_.set_output_mode(MOS::MOS6560::OutputMode::NTSC); - } else { - // PAL - set_clock_rate(1108404); - mos6560_.set_output_mode(MOS::MOS6560::OutputMode::PAL); - } + // Determine PAL/NTSC + if(target.region == Analyser::Static::Commodore::Target::Region::American || target.region == Analyser::Static::Commodore::Target::Region::Japanese) { + // NTSC + set_clock_rate(1022727); + mos6560_.set_output_mode(MOS::MOS6560::OutputMode::NTSC); + } else { + // PAL + set_clock_rate(1108404); + mos6560_.set_output_mode(MOS::MOS6560::OutputMode::PAL); + } - mos6560_.set_high_frequency_cutoff(1600); // There is a 1.6Khz low-pass filter in the Vic-20. - mos6560_.set_clock_rate(get_clock_rate()); + mos6560_.set_high_frequency_cutoff(1600); // There is a 1.6Khz low-pass filter in the Vic-20. + mos6560_.set_clock_rate(get_clock_rate()); - // Initialise the memory maps as all pointing to nothing - memset(processor_read_memory_map_, 0, sizeof(processor_read_memory_map_)); - memset(processor_write_memory_map_, 0, sizeof(processor_write_memory_map_)); - memset(mos6560_bus_handler_.video_memory_map, 0, sizeof(mos6560_bus_handler_.video_memory_map)); + // Initialise the memory maps as all pointing to nothing + memset(processor_read_memory_map_, 0, sizeof(processor_read_memory_map_)); + memset(processor_write_memory_map_, 0, sizeof(processor_write_memory_map_)); + memset(mos6560_bus_handler_.video_memory_map, 0, sizeof(mos6560_bus_handler_.video_memory_map)); #define set_ram(baseaddr, length) { \ - write_to_map(processor_read_memory_map_, &ram_[baseaddr], baseaddr, length); \ - write_to_map(processor_write_memory_map_, &ram_[baseaddr], baseaddr, length); \ - } + write_to_map(processor_read_memory_map_, &ram_[baseaddr], baseaddr, length); \ + write_to_map(processor_write_memory_map_, &ram_[baseaddr], baseaddr, length); \ +} - // Add 6502-visible RAM as requested. - set_ram(0x0000, 0x0400); - set_ram(0x1000, 0x1000); // Built-in RAM. - if(target.enabled_ram.bank0) set_ram(0x0400, 0x0c00); // Bank 0: 0x0400 -> 0x1000. - if(target.enabled_ram.bank1) set_ram(0x2000, 0x2000); // Bank 1: 0x2000 -> 0x4000. - if(target.enabled_ram.bank2) set_ram(0x4000, 0x2000); // Bank 2: 0x4000 -> 0x6000. - if(target.enabled_ram.bank3) set_ram(0x6000, 0x2000); // Bank 3: 0x6000 -> 0x8000. - if(target.enabled_ram.bank5) set_ram(0xa000, 0x2000); // Bank 5: 0xa000 -> 0xc000. + // Add 6502-visible RAM as requested. + set_ram(0x0000, 0x0400); + set_ram(0x1000, 0x1000); // Built-in RAM. + if(target.enabled_ram.bank0) set_ram(0x0400, 0x0c00); // Bank 0: 0x0400 -> 0x1000. + if(target.enabled_ram.bank1) set_ram(0x2000, 0x2000); // Bank 1: 0x2000 -> 0x4000. + if(target.enabled_ram.bank2) set_ram(0x4000, 0x2000); // Bank 2: 0x4000 -> 0x6000. + if(target.enabled_ram.bank3) set_ram(0x6000, 0x2000); // Bank 3: 0x6000 -> 0x8000. + if(target.enabled_ram.bank5) set_ram(0xa000, 0x2000); // Bank 5: 0xa000 -> 0xc000. #undef set_ram - // all expansions also have colour RAM visible at 0x9400. - write_to_map(processor_read_memory_map_, colour_ram_, 0x9400, sizeof(colour_ram_)); - write_to_map(processor_write_memory_map_, colour_ram_, 0x9400, sizeof(colour_ram_)); + // all expansions also have colour RAM visible at 0x9400. + write_to_map(processor_read_memory_map_, colour_ram_, 0x9400, sizeof(colour_ram_)); + write_to_map(processor_write_memory_map_, colour_ram_, 0x9400, sizeof(colour_ram_)); - // also push memory resources into the 6560 video memory map; the 6560 has only a - // 14-bit address bus and the top bit is invested and used as bit 15 for the main - // memory bus. It can access only internal memory, so the first 1kb, then the 4kb from 0x1000. - struct Range { - const std::size_t start, end; - Range(std::size_t start, std::size_t end) : start(start), end(end) {} - }; - const std::array video_ranges = {{ - Range(0x0000, 0x0400), - Range(0x1000, 0x2000), - }}; - for(const auto &video_range : video_ranges) { - for(auto addr = video_range.start; addr < video_range.end; addr += 0x400) { - auto destination_address = (addr & 0x1fff) | (((addr & 0x8000) >> 2) ^ 0x2000); - if(processor_read_memory_map_[addr >> 10]) { - write_to_map(mos6560_bus_handler_.video_memory_map, &ram_[addr], uint16_t(destination_address), 0x400); - } + // also push memory resources into the 6560 video memory map; the 6560 has only a + // 14-bit address bus and the top bit is invested and used as bit 15 for the main + // memory bus. It can access only internal memory, so the first 1kb, then the 4kb from 0x1000. + struct Range { + const std::size_t start, end; + Range(std::size_t start, std::size_t end) : start(start), end(end) {} + }; + const std::array video_ranges = {{ + Range(0x0000, 0x0400), + Range(0x1000, 0x2000), + }}; + for(const auto &video_range : video_ranges) { + for(auto addr = video_range.start; addr < video_range.end; addr += 0x400) { + auto destination_address = (addr & 0x1fff) | (((addr & 0x8000) >> 2) ^ 0x2000); + if(processor_read_memory_map_[addr >> 10]) { + write_to_map(mos6560_bus_handler_.video_memory_map, &ram_[addr], uint16_t(destination_address), 0x400); } } - mos6560_bus_handler_.colour_memory = colour_ram_; + } + mos6560_bus_handler_.colour_memory = colour_ram_; - // install the BASIC ROM - write_to_map(processor_read_memory_map_, basic_rom_.data(), 0xc000, uint16_t(basic_rom_.size())); + // install the BASIC ROM + write_to_map(processor_read_memory_map_, basic_rom_.data(), 0xc000, uint16_t(basic_rom_.size())); - // install the system ROM - write_to_map(processor_read_memory_map_, character_rom_.data(), 0x8000, uint16_t(character_rom_.size())); - write_to_map(mos6560_bus_handler_.video_memory_map, character_rom_.data(), 0x0000, uint16_t(character_rom_.size())); - write_to_map(processor_read_memory_map_, kernel_rom_.data(), 0xe000, uint16_t(kernel_rom_.size())); + // install the system ROM + write_to_map(processor_read_memory_map_, character_rom_.data(), 0x8000, uint16_t(character_rom_.size())); + write_to_map(mos6560_bus_handler_.video_memory_map, character_rom_.data(), 0x0000, uint16_t(character_rom_.size())); + write_to_map(processor_read_memory_map_, kernel_rom_.data(), 0xe000, uint16_t(kernel_rom_.size())); - // The insert_media occurs last, so if there's a conflict between cartridges and RAM, - // the cartridge wins. - insert_media(target.media); - if(!target.loading_command.empty()) { - type_string(target.loading_command); - } + // The insert_media occurs last, so if there's a conflict between cartridges and RAM, + // the cartridge wins. + insert_media(target.media); + if(!target.loading_command.empty()) { + type_string(target.loading_command); + } + } + + bool insert_media(const Analyser::Static::Media &media) final { + if(!media.tapes.empty()) { + tape_->set_tape(media.tapes.front()); } - bool insert_media(const Analyser::Static::Media &media) final { - if(!media.tapes.empty()) { - tape_->set_tape(media.tapes.front()); - } - - if(!media.disks.empty() && c1540_) { - c1540_->set_disk(media.disks.front()); - } - - if(!media.cartridges.empty()) { - rom_address_ = 0xa000; - std::vector rom_image = media.cartridges.front()->get_segments().front().data; - rom_length_ = uint16_t(rom_image.size()); - - rom_ = rom_image; - rom_.resize(0x2000); - write_to_map(processor_read_memory_map_, rom_.data(), rom_address_, rom_length_); - } - - set_use_fast_tape(); - - return !media.tapes.empty() || (!media.disks.empty() && c1540_ != nullptr) || !media.cartridges.empty(); + if(!media.disks.empty() && c1540_) { + c1540_->set_disk(media.disks.front()); } - void set_key_state(uint16_t key, bool is_pressed) final { - if(key < 0xfff0) { - keyboard_via_port_handler_->set_key_state(key, is_pressed); - } else { - switch(key) { - case KeyRestore: - user_port_via_.set_control_line_input(MOS::MOS6522::Port::A, MOS::MOS6522::Line::One, !is_pressed); - break; + if(!media.cartridges.empty()) { + rom_address_ = 0xa000; + std::vector rom_image = media.cartridges.front()->get_segments().front().data; + rom_length_ = uint16_t(rom_image.size()); + + rom_ = rom_image; + rom_.resize(0x2000); + write_to_map(processor_read_memory_map_, rom_.data(), rom_address_, rom_length_); + } + + set_use_fast_tape(); + + return !media.tapes.empty() || (!media.disks.empty() && c1540_ != nullptr) || !media.cartridges.empty(); + } + + void set_key_state(uint16_t key, bool is_pressed) final { + if(key < 0xfff0) { + keyboard_via_port_handler_->set_key_state(key, is_pressed); + } else { + switch(key) { + case KeyRestore: + user_port_via_.set_control_line_input(MOS::MOS6522::Port::A, MOS::MOS6522::Line::One, !is_pressed); + break; #define ShiftedMap(source, target) \ - case source: \ - keyboard_via_port_handler_->set_key_state(KeyLShift, is_pressed); \ - keyboard_via_port_handler_->set_key_state(target, is_pressed); \ - break; + case source: \ + keyboard_via_port_handler_->set_key_state(KeyLShift, is_pressed); \ + keyboard_via_port_handler_->set_key_state(target, is_pressed); \ + break; - ShiftedMap(KeyUp, KeyDown); - ShiftedMap(KeyLeft, KeyRight); - ShiftedMap(KeyF2, KeyF1); - ShiftedMap(KeyF4, KeyF3); - ShiftedMap(KeyF6, KeyF5); - ShiftedMap(KeyF8, KeyF7); + ShiftedMap(KeyUp, KeyDown); + ShiftedMap(KeyLeft, KeyRight); + ShiftedMap(KeyF2, KeyF1); + ShiftedMap(KeyF4, KeyF3); + ShiftedMap(KeyF6, KeyF5); + ShiftedMap(KeyF8, KeyF7); #undef ShiftedMap - } } } + } - void clear_all_keys() final { - keyboard_via_port_handler_->clear_all_keys(); - } + void clear_all_keys() final { + keyboard_via_port_handler_->clear_all_keys(); + } - const std::vector> &get_joysticks() final { - return joysticks_; - } + const std::vector> &get_joysticks() final { + return joysticks_; + } - // to satisfy CPU::MOS6502::Processor - forceinline Cycles perform_bus_operation(CPU::MOS6502::BusOperation operation, uint16_t address, uint8_t *value) { - // run the phase-1 part of this cycle, in which the VIC accesses memory - cycles_since_mos6560_update_++; + // to satisfy CPU::MOS6502::Processor + forceinline Cycles perform_bus_operation(CPU::MOS6502::BusOperation operation, uint16_t address, uint8_t *value) { + // run the phase-1 part of this cycle, in which the VIC accesses memory + cycles_since_mos6560_update_++; - // run the phase-2 part of the cycle, which is whatever the 6502 said it should be - if(isReadOperation(operation)) { - uint8_t result = processor_read_memory_map_[address >> 10] ? processor_read_memory_map_[address >> 10][address & 0x3ff] : 0xff; - if((address&0xfc00) == 0x9000) { - if(!(address&0x100)) { - update_video(); - result &= mos6560_.read(address); - } - if(address & 0x10) result &= user_port_via_.read(address); - if(address & 0x20) result &= keyboard_via_.read(address); + // run the phase-2 part of the cycle, which is whatever the 6502 said it should be + if(isReadOperation(operation)) { + uint8_t result = processor_read_memory_map_[address >> 10] ? processor_read_memory_map_[address >> 10][address & 0x3ff] : 0xff; + if((address&0xfc00) == 0x9000) { + if(!(address&0x100)) { + update_video(); + result &= mos6560_.read(address); } - *value = result; + if(address & 0x10) result &= user_port_via_.read(address); + if(address & 0x20) result &= keyboard_via_.read(address); + } + *value = result; - // Consider applying the fast tape hack. - if(use_fast_tape_hack_ && operation == CPU::MOS6502::BusOperation::ReadOpcode) { - if(address == 0xf7b2) { - // Address 0xf7b2 contains a JSR to 0xf8c0 that will fill the tape buffer with the next header. - // So cancel that via a double NOP and fill in the next header programmatically. + // Consider applying the fast tape hack. + if(use_fast_tape_hack_ && operation == CPU::MOS6502::BusOperation::ReadOpcode) { + if(address == 0xf7b2) { + // Address 0xf7b2 contains a JSR to 0xf8c0 that will fill the tape buffer with the next header. + // So cancel that via a double NOP and fill in the next header programmatically. + Storage::Tape::Commodore::Parser parser; + std::unique_ptr header = parser.get_next_header(tape_->tape()); + + const auto tape_position = tape_->tape()->offset(); + if(header) { + // serialise to wherever b2:b3 points + const uint16_t tape_buffer_pointer = uint16_t(ram_[0xb2]) | uint16_t(ram_[0xb3] << 8); + header->serialise(&ram_[tape_buffer_pointer], 0x8000 - tape_buffer_pointer); + hold_tape_ = true; + logger.info().append("Found header"); + } else { + // no header found, so pretend this hack never interceded + tape_->tape()->set_offset(tape_position); + hold_tape_ = false; + logger.info().append("Didn't find header"); + } + + // clear status and the verify flag + ram_[0x90] = 0; + ram_[0x93] = 0; + + *value = 0x0c; // i.e. NOP abs, to swallow the entire JSR + } else if(address == 0xf90b) { + uint8_t x = uint8_t(m6502_.value_of(CPU::MOS6502::Register::X)); + if(x == 0xe) { Storage::Tape::Commodore::Parser parser; - std::unique_ptr header = parser.get_next_header(tape_->tape()); - const auto tape_position = tape_->tape()->offset(); - if(header) { - // serialise to wherever b2:b3 points - const uint16_t tape_buffer_pointer = uint16_t(ram_[0xb2]) | uint16_t(ram_[0xb3] << 8); - header->serialise(&ram_[tape_buffer_pointer], 0x8000 - tape_buffer_pointer); + const std::unique_ptr data = parser.get_next_data(tape_->tape()); + if(data) { + uint16_t start_address, end_address; + start_address = uint16_t(ram_[0xc1] | (ram_[0xc2] << 8)); + end_address = uint16_t(ram_[0xae] | (ram_[0xaf] << 8)); + + // perform a via-processor_write_memory_map_ memcpy + uint8_t *data_ptr = data->data.data(); + std::size_t data_left = data->data.size(); + while(data_left && start_address != end_address) { + uint8_t *page = processor_write_memory_map_[start_address >> 10]; + if(page) page[start_address & 0x3ff] = *data_ptr; + data_ptr++; + start_address++; + data_left--; + } + + // set tape status, carry and flag + ram_[0x90] |= 0x40; + uint8_t flags = uint8_t(m6502_.value_of(CPU::MOS6502::Register::Flags)); + flags &= ~uint8_t((CPU::MOS6502::Flag::Carry | CPU::MOS6502::Flag::Interrupt)); + m6502_.set_value_of(CPU::MOS6502::Register::Flags, flags); + + // to ensure that execution proceeds to 0xfccf, pretend a NOP was here and + // ensure that the PC leaps to 0xfccf + m6502_.set_value_of(CPU::MOS6502::Register::ProgramCounter, 0xfccf); + *value = 0xea; // i.e. NOP implied hold_tape_ = true; - logger.info().append("Found header"); + logger.info().append("Found data"); } else { - // no header found, so pretend this hack never interceded tape_->tape()->set_offset(tape_position); hold_tape_ = false; - logger.info().append("Didn't find header"); - } - - // clear status and the verify flag - ram_[0x90] = 0; - ram_[0x93] = 0; - - *value = 0x0c; // i.e. NOP abs, to swallow the entire JSR - } else if(address == 0xf90b) { - uint8_t x = uint8_t(m6502_.value_of(CPU::MOS6502::Register::X)); - if(x == 0xe) { - Storage::Tape::Commodore::Parser parser; - const auto tape_position = tape_->tape()->offset(); - const std::unique_ptr data = parser.get_next_data(tape_->tape()); - if(data) { - uint16_t start_address, end_address; - start_address = uint16_t(ram_[0xc1] | (ram_[0xc2] << 8)); - end_address = uint16_t(ram_[0xae] | (ram_[0xaf] << 8)); - - // perform a via-processor_write_memory_map_ memcpy - uint8_t *data_ptr = data->data.data(); - std::size_t data_left = data->data.size(); - while(data_left && start_address != end_address) { - uint8_t *page = processor_write_memory_map_[start_address >> 10]; - if(page) page[start_address & 0x3ff] = *data_ptr; - data_ptr++; - start_address++; - data_left--; - } - - // set tape status, carry and flag - ram_[0x90] |= 0x40; - uint8_t flags = uint8_t(m6502_.value_of(CPU::MOS6502::Register::Flags)); - flags &= ~uint8_t((CPU::MOS6502::Flag::Carry | CPU::MOS6502::Flag::Interrupt)); - m6502_.set_value_of(CPU::MOS6502::Register::Flags, flags); - - // to ensure that execution proceeds to 0xfccf, pretend a NOP was here and - // ensure that the PC leaps to 0xfccf - m6502_.set_value_of(CPU::MOS6502::Register::ProgramCounter, 0xfccf); - *value = 0xea; // i.e. NOP implied - hold_tape_ = true; - logger.info().append("Found data"); - } else { - tape_->tape()->set_offset(tape_position); - hold_tape_ = false; - logger.info().append("Didn't find data"); - } + logger.info().append("Didn't find data"); } } } - } else { - uint8_t *ram = processor_write_memory_map_[address >> 10]; - if(ram) { - update_video(); - ram[address & 0x3ff] = *value; - } - // Anything between 0x9000 and 0x9400 is the IO area. - if((address&0xfc00) == 0x9000) { - // The VIC is selected by bit 8 = 0 - if(!(address&0x100)) { - update_video(); - mos6560_.write(address, *value); - } - // The first VIA is selected by bit 4 = 1. - if(address & 0x10) user_port_via_.write(address, *value); - // The second VIA is selected by bit 5 = 1. - if(address & 0x20) keyboard_via_.write(address, *value); - } } - - user_port_via_.run_for(Cycles(1)); - keyboard_via_.run_for(Cycles(1)); - if(typer_ && address == 0xeb1e && operation == CPU::MOS6502::BusOperation::ReadOpcode) { - if(!typer_->type_next_character()) { - clear_all_keys(); - typer_.reset(); - } - } - if(!tape_is_sleeping_ && !hold_tape_) tape_->run_for(Cycles(1)); - if(c1540_) c1540_->run_for(Cycles(1)); - - return Cycles(1); - } - - void flush_output(int outputs) final { - if(outputs & Output::Video) { + } else { + uint8_t *ram = processor_write_memory_map_[address >> 10]; + if(ram) { update_video(); + ram[address & 0x3ff] = *value; } - if(outputs & Output::Audio) { - mos6560_.flush(); + // Anything between 0x9000 and 0x9400 is the IO area. + if((address&0xfc00) == 0x9000) { + // The VIC is selected by bit 8 = 0 + if(!(address&0x100)) { + update_video(); + mos6560_.write(address, *value); + } + // The first VIA is selected by bit 4 = 1. + if(address & 0x10) user_port_via_.write(address, *value); + // The second VIA is selected by bit 5 = 1. + if(address & 0x20) keyboard_via_.write(address, *value); } } - void run_for(const Cycles cycles) final { - m6502_.run_for(cycles); - } - - void set_scan_target(Outputs::Display::ScanTarget *scan_target) final { - mos6560_.set_scan_target(scan_target); - } - - Outputs::Display::ScanStatus get_scaled_scan_status() const final { - return mos6560_.get_scaled_scan_status(); - } - - void set_display_type(Outputs::Display::DisplayType display_type) final { - mos6560_.set_display_type(display_type); - } - - Outputs::Display::DisplayType get_display_type() const final { - return mos6560_.get_display_type(); - } - - Outputs::Speaker::Speaker *get_speaker() final { - return mos6560_.get_speaker(); - } - - void mos6522_did_change_interrupt_status(void *) final { - m6502_.set_nmi_line(user_port_via_.get_interrupt_line()); - m6502_.set_irq_line(keyboard_via_.get_interrupt_line()); - } - - void type_string(const std::string &string) final { - Utility::TypeRecipient::add_typer(string); - } - - bool can_type(char c) const final { - return Utility::TypeRecipient::can_type(c); - } - - void tape_did_change_input(Storage::Tape::BinaryTapePlayer *tape) final { - keyboard_via_.set_control_line_input(MOS::MOS6522::Port::A, MOS::MOS6522::Line::One, !tape->input()); - } - - KeyboardMapper *get_keyboard_mapper() final { - return &keyboard_mapper_; - } - - // MARK: - Configuration options. - std::unique_ptr get_options() const final { - auto options = std::make_unique(Configurable::OptionsType::UserFriendly); - options->output = get_video_signal_configurable(); - options->quickload = allow_fast_tape_hack_; - return options; - } - - void set_options(const std::unique_ptr &str) final { - const auto options = dynamic_cast(str.get()); - - set_video_signal_configurable(options->output); - allow_fast_tape_hack_ = options->quickload; - set_use_fast_tape(); - } - - void set_component_prefers_clocking(ClockingHint::Source *, ClockingHint::Preference clocking) final { - tape_is_sleeping_ = clocking == ClockingHint::Preference::None; - set_use_fast_tape(); - } - - // MARK: - Activity Source - void set_activity_observer(Activity::Observer *observer) final { - if(c1540_) c1540_->set_activity_observer(observer); - } - - private: - void update_video() { - mos6560_.run_for(cycles_since_mos6560_update_.flush()); - } - CPU::MOS6502::Processor m6502_; - - std::vector character_rom_; - std::vector basic_rom_; - std::vector kernel_rom_; - - std::vector rom_; - uint16_t rom_address_, rom_length_; - uint8_t ram_[0x10000]; - uint8_t colour_ram_[0x0400]; - - uint8_t *processor_read_memory_map_[64]; - uint8_t *processor_write_memory_map_[64]; - void write_to_map(uint8_t **map, uint8_t *area, uint16_t address, uint16_t length) { - address >>= 10; - length >>= 10; - while(length--) { - map[address] = area; - area += 0x400; - address++; + user_port_via_.run_for(Cycles(1)); + keyboard_via_.run_for(Cycles(1)); + if(typer_ && address == 0xeb1e && operation == CPU::MOS6502::BusOperation::ReadOpcode) { + if(!typer_->type_next_character()) { + clear_all_keys(); + typer_.reset(); } } + if(!tape_is_sleeping_ && !hold_tape_) tape_->run_for(Cycles(1)); + if(c1540_) c1540_->run_for(Cycles(1)); - Commodore::Vic20::KeyboardMapper keyboard_mapper_; - std::vector> joysticks_; + return Cycles(1); + } - Cycles cycles_since_mos6560_update_; - Vic6560BusHandler mos6560_bus_handler_; - MOS::MOS6560::MOS6560 mos6560_; - std::shared_ptr user_port_via_port_handler_; - std::shared_ptr keyboard_via_port_handler_; - std::shared_ptr serial_port_; - std::shared_ptr<::Commodore::Serial::Bus> serial_bus_; - - MOS::MOS6522::MOS6522 user_port_via_; - MOS::MOS6522::MOS6522 keyboard_via_; - - // Tape - std::shared_ptr tape_; - bool use_fast_tape_hack_ = false; - bool hold_tape_ = false; - bool allow_fast_tape_hack_ = false; - bool tape_is_sleeping_ = true; - void set_use_fast_tape() { - use_fast_tape_hack_ = !tape_is_sleeping_ && allow_fast_tape_hack_ && tape_->has_tape(); + void flush_output(int outputs) final { + if(outputs & Output::Video) { + update_video(); } + if(outputs & Output::Audio) { + mos6560_.flush(); + } + } - // Disk - std::shared_ptr<::Commodore::C1540::Machine> c1540_; + void run_for(const Cycles cycles) final { + m6502_.run_for(cycles); + } + + void set_scan_target(Outputs::Display::ScanTarget *scan_target) final { + mos6560_.set_scan_target(scan_target); + } + + Outputs::Display::ScanStatus get_scaled_scan_status() const final { + return mos6560_.get_scaled_scan_status(); + } + + void set_display_type(Outputs::Display::DisplayType display_type) final { + mos6560_.set_display_type(display_type); + } + + Outputs::Display::DisplayType get_display_type() const final { + return mos6560_.get_display_type(); + } + + Outputs::Speaker::Speaker *get_speaker() final { + return mos6560_.get_speaker(); + } + + void mos6522_did_change_interrupt_status(void *) final { + m6502_.set_nmi_line(user_port_via_.get_interrupt_line()); + m6502_.set_irq_line(keyboard_via_.get_interrupt_line()); + } + + void type_string(const std::string &string) final { + Utility::TypeRecipient::add_typer(string); + } + + bool can_type(char c) const final { + return Utility::TypeRecipient::can_type(c); + } + + void tape_did_change_input(Storage::Tape::BinaryTapePlayer *tape) final { + keyboard_via_.set_control_line_input(MOS::MOS6522::Port::A, MOS::MOS6522::Line::One, !tape->input()); + } + + KeyboardMapper *get_keyboard_mapper() final { + return &keyboard_mapper_; + } + + // MARK: - Configuration options. + std::unique_ptr get_options() const final { + auto options = std::make_unique(Configurable::OptionsType::UserFriendly); + options->output = get_video_signal_configurable(); + options->quickload = allow_fast_tape_hack_; + return options; + } + + void set_options(const std::unique_ptr &str) final { + const auto options = dynamic_cast(str.get()); + + set_video_signal_configurable(options->output); + allow_fast_tape_hack_ = options->quickload; + set_use_fast_tape(); + } + + void set_component_prefers_clocking(ClockingHint::Source *, ClockingHint::Preference clocking) final { + tape_is_sleeping_ = clocking == ClockingHint::Preference::None; + set_use_fast_tape(); + } + + // MARK: - Activity Source + void set_activity_observer(Activity::Observer *observer) final { + if(c1540_) c1540_->set_activity_observer(observer); + } + +private: + void update_video() { + mos6560_.run_for(cycles_since_mos6560_update_.flush()); + } + CPU::MOS6502::Processor m6502_; + + std::vector character_rom_; + std::vector basic_rom_; + std::vector kernel_rom_; + + std::vector rom_; + uint16_t rom_address_, rom_length_; + uint8_t ram_[0x10000]; + uint8_t colour_ram_[0x0400]; + + uint8_t *processor_read_memory_map_[64]; + uint8_t *processor_write_memory_map_[64]; + void write_to_map(uint8_t **map, uint8_t *area, uint16_t address, uint16_t length) { + address >>= 10; + length >>= 10; + while(length--) { + map[address] = area; + area += 0x400; + address++; + } + } + + Commodore::Vic20::KeyboardMapper keyboard_mapper_; + std::vector> joysticks_; + + Cycles cycles_since_mos6560_update_; + Vic6560BusHandler mos6560_bus_handler_; + MOS::MOS6560::MOS6560 mos6560_; + std::shared_ptr user_port_via_port_handler_; + std::shared_ptr keyboard_via_port_handler_; + std::shared_ptr serial_port_; + std::shared_ptr<::Commodore::Serial::Bus> serial_bus_; + + MOS::MOS6522::MOS6522 user_port_via_; + MOS::MOS6522::MOS6522 keyboard_via_; + + // Tape + std::shared_ptr tape_; + bool use_fast_tape_hack_ = false; + bool hold_tape_ = false; + bool allow_fast_tape_hack_ = false; + bool tape_is_sleeping_ = true; + void set_use_fast_tape() { + use_fast_tape_hack_ = !tape_is_sleeping_ && allow_fast_tape_hack_ && tape_->has_tape(); + } + + // Disk + std::shared_ptr<::Commodore::C1540::Machine> c1540_; }; } using namespace Commodore::Vic20; -std::unique_ptr Machine::Vic20(const Analyser::Static::Target *target, const ROMMachine::ROMFetcher &rom_fetcher) { +std::unique_ptr Machine::Vic20( + const Analyser::Static::Target *target, + const ROMMachine::ROMFetcher &rom_fetcher +) { using Target = Analyser::Static::Commodore::Target; const Target *const commodore_target = dynamic_cast(target); return std::make_unique(*commodore_target, rom_fetcher); diff --git a/Machines/Commodore/Vic-20/Vic20.hpp b/Machines/Commodore/Vic-20/Vic20.hpp index e21ae244f..425a1fd74 100644 --- a/Machines/Commodore/Vic-20/Vic20.hpp +++ b/Machines/Commodore/Vic-20/Vic20.hpp @@ -21,26 +21,26 @@ namespace Commodore::Vic20 { std::unique_ptr get_options(); class Machine { - public: - virtual ~Machine() = default; +public: + virtual ~Machine() = default; - /// Creates and returns a Vic-20. - static std::unique_ptr Vic20(const Analyser::Static::Target *target, const ROMMachine::ROMFetcher &rom_fetcher); + /// Creates and returns a Vic-20. + static std::unique_ptr Vic20(const Analyser::Static::Target *, const ROMMachine::ROMFetcher &); - class Options: public Reflection::StructImpl, public Configurable::DisplayOption, public Configurable::QuickloadOption { - friend Configurable::DisplayOption; - friend Configurable::QuickloadOption; - public: - Options(Configurable::OptionsType type) : - Configurable::DisplayOption(type == Configurable::OptionsType::UserFriendly ? Configurable::Display::SVideo : Configurable::Display::CompositeColour), - Configurable::QuickloadOption(type == Configurable::OptionsType::UserFriendly) { - if(needs_declare()) { - declare_display_option(); - declare_quickload_option(); - limit_enum(&output, Configurable::Display::SVideo, Configurable::Display::CompositeColour, -1); - } + class Options: public Reflection::StructImpl, public Configurable::DisplayOption, public Configurable::QuickloadOption { + friend Configurable::DisplayOption; + friend Configurable::QuickloadOption; + public: + Options(Configurable::OptionsType type) : + Configurable::DisplayOption(type == Configurable::OptionsType::UserFriendly ? Configurable::Display::SVideo : Configurable::Display::CompositeColour), + Configurable::QuickloadOption(type == Configurable::OptionsType::UserFriendly) { + if(needs_declare()) { + declare_display_option(); + declare_quickload_option(); + limit_enum(&output, Configurable::Display::SVideo, Configurable::Display::CompositeColour, -1); } - }; + } + }; }; }