mirror of
https://github.com/TomHarte/CLK.git
synced 2025-01-12 15:31:09 +00:00
Performed the normative removal from public view of Vic-20 implementation details. Which were hefty.
This commit is contained in:
parent
3c50903a2b
commit
4c15e46fd1
@ -8,15 +8,181 @@
|
|||||||
|
|
||||||
#include "Vic20.hpp"
|
#include "Vic20.hpp"
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include "../../../Storage/Tape/Formats/TapePRG.hpp"
|
|
||||||
#include "../../../Storage/Tape/Parsers/Commodore.hpp"
|
|
||||||
#include "../../../StaticAnalyser/StaticAnalyser.hpp"
|
|
||||||
#include "CharacterMapper.hpp"
|
#include "CharacterMapper.hpp"
|
||||||
|
|
||||||
using namespace Commodore::Vic20;
|
#include "../../../Processors/6502/6502.hpp"
|
||||||
|
#include "../../../Components/6560/6560.hpp"
|
||||||
|
#include "../../../Components/6522/6522.hpp"
|
||||||
|
|
||||||
Machine::Machine() :
|
#include "../../../Storage/Tape/Parsers/Commodore.hpp"
|
||||||
|
|
||||||
|
#include "../SerialBus.hpp"
|
||||||
|
#include "../1540/C1540.hpp"
|
||||||
|
|
||||||
|
#include "../../../Storage/Tape/Tape.hpp"
|
||||||
|
#include "../../../Storage/Disk/Disk.hpp"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
namespace Commodore {
|
||||||
|
namespace Vic20 {
|
||||||
|
|
||||||
|
class UserPortVIA: public MOS::MOS6522<UserPortVIA>, public MOS::MOS6522IRQDelegate {
|
||||||
|
public:
|
||||||
|
UserPortVIA() : port_a_(0xbf) {}
|
||||||
|
using MOS6522IRQDelegate::set_interrupt_status;
|
||||||
|
|
||||||
|
uint8_t get_port_input(Port port) {
|
||||||
|
if(!port) {
|
||||||
|
return port_a_ | (tape_->has_tape() ? 0x00 : 0x40);
|
||||||
|
}
|
||||||
|
return 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_control_line_output(Port port, Line line, bool value) {
|
||||||
|
if(port == Port::A && line == Line::Two) {
|
||||||
|
tape_->set_motor_control(!value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_joystick_state(JoystickInput input, bool value) {
|
||||||
|
if(input != JoystickInput::Right) {
|
||||||
|
port_a_ = (port_a_ & ~input) | (value ? 0 : input);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_port_output(Port port, uint8_t value, uint8_t mask) {
|
||||||
|
// 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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_serial_port(std::shared_ptr<::Commodore::Serial::Port> serialPort) {
|
||||||
|
serial_port_ = serialPort;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_tape(std::shared_ptr<Storage::Tape::BinaryTapePlayer> tape) {
|
||||||
|
tape_ = tape;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint8_t port_a_;
|
||||||
|
std::weak_ptr<::Commodore::Serial::Port> serial_port_;
|
||||||
|
std::shared_ptr<Storage::Tape::BinaryTapePlayer> tape_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class KeyboardVIA: public MOS::MOS6522<KeyboardVIA>, public MOS::MOS6522IRQDelegate {
|
||||||
|
public:
|
||||||
|
KeyboardVIA() : port_b_(0xff) {
|
||||||
|
clear_all_keys();
|
||||||
|
}
|
||||||
|
|
||||||
|
using MOS6522IRQDelegate::set_interrupt_status;
|
||||||
|
|
||||||
|
void set_key_state(uint16_t key, bool isPressed) {
|
||||||
|
if(isPressed)
|
||||||
|
columns_[key & 7] &= ~(key >> 3);
|
||||||
|
else
|
||||||
|
columns_[key & 7] |= (key >> 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear_all_keys() {
|
||||||
|
memset(columns_, 0xff, sizeof(columns_));
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t get_port_input(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;
|
||||||
|
}
|
||||||
|
|
||||||
|
return port_b_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_port_output(Port port, uint8_t value, uint8_t mask) {
|
||||||
|
if(port)
|
||||||
|
activation_mask_ = (value & mask) | (~mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_control_line_output(Port port, Line line, bool value) {
|
||||||
|
if(line == 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 == 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_joystick_state(JoystickInput input, bool value) {
|
||||||
|
if(input == JoystickInput::Right) {
|
||||||
|
port_b_ = (port_b_ & ~input) | (value ? 0 : input);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class SerialPort : public ::Commodore::Serial::Port {
|
||||||
|
public:
|
||||||
|
void set_input(::Commodore::Serial::Line line, ::Commodore::Serial::LineLevel level) {
|
||||||
|
std::shared_ptr<UserPortVIA> userPortVIA = user_port_via_.lock();
|
||||||
|
if(userPortVIA) userPortVIA->set_serial_line_state(line, (bool)level);
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_user_port_via(std::shared_ptr<UserPortVIA> userPortVIA) {
|
||||||
|
user_port_via_ = userPortVIA;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::weak_ptr<UserPortVIA> user_port_via_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Vic6560: public MOS::MOS6560<Vic6560> {
|
||||||
|
public:
|
||||||
|
inline 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];
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t *video_memory_map[16];
|
||||||
|
uint8_t *colour_memory;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ConcreteMachine:
|
||||||
|
public CPU::MOS6502::BusHandler,
|
||||||
|
public MOS::MOS6522IRQDelegate::Delegate,
|
||||||
|
public Utility::TypeRecipient,
|
||||||
|
public Storage::Tape::BinaryTapePlayer::Delegate,
|
||||||
|
public Machine {
|
||||||
|
public:
|
||||||
|
ConcreteMachine() :
|
||||||
m6502_(*this),
|
m6502_(*this),
|
||||||
rom_(nullptr),
|
rom_(nullptr),
|
||||||
is_running_at_zero_cost_(false),
|
is_running_at_zero_cost_(false),
|
||||||
@ -51,7 +217,90 @@ Machine::Machine() :
|
|||||||
// serial_bus_->add_port(_debugPort);
|
// serial_bus_->add_port(_debugPort);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Machine::set_memory_size(MemorySize size) {
|
~ConcreteMachine() {
|
||||||
|
delete[] rom_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_rom(ROMSlot slot, size_t length, const uint8_t *data) {
|
||||||
|
uint8_t *target = nullptr;
|
||||||
|
size_t max_length = 0x2000;
|
||||||
|
switch(slot) {
|
||||||
|
case Kernel: target = kernel_rom_; break;
|
||||||
|
case Characters: target = character_rom_; max_length = 0x1000; break;
|
||||||
|
case BASIC: target = basic_rom_; break;
|
||||||
|
case Drive:
|
||||||
|
drive_rom_.resize(length);
|
||||||
|
memcpy(drive_rom_.data(), data, length);
|
||||||
|
install_disk_rom();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(target) {
|
||||||
|
size_t length_to_copy = std::min(max_length, length);
|
||||||
|
memcpy(target, data, length_to_copy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void configure_as_target(const StaticAnalyser::Target &target) {
|
||||||
|
if(target.tapes.size()) {
|
||||||
|
tape_->set_tape(target.tapes.front());
|
||||||
|
}
|
||||||
|
|
||||||
|
if(target.disks.size()) {
|
||||||
|
// construct the 1540
|
||||||
|
c1540_.reset(new ::Commodore::C1540::Machine);
|
||||||
|
|
||||||
|
// attach it to the serial bus
|
||||||
|
c1540_->set_serial_bus(serial_bus_);
|
||||||
|
|
||||||
|
// hand it the disk
|
||||||
|
c1540_->set_disk(target.disks.front());
|
||||||
|
|
||||||
|
// install the ROM if it was previously set
|
||||||
|
install_disk_rom();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(target.cartridges.size()) {
|
||||||
|
rom_address_ = 0xa000;
|
||||||
|
std::vector<uint8_t> rom_image = target.cartridges.front()->get_segments().front().data;
|
||||||
|
rom_length_ = (uint16_t)(rom_image.size());
|
||||||
|
|
||||||
|
rom_ = new uint8_t[0x2000];
|
||||||
|
memcpy(rom_, rom_image.data(), rom_image.size());
|
||||||
|
write_to_map(processor_read_memory_map_, rom_, rom_address_, 0x2000);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(target.loadingCommand.length()) {
|
||||||
|
set_typer_for_string(target.loadingCommand.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(target.vic20.memory_model) {
|
||||||
|
case StaticAnalyser::Vic20MemoryModel::Unexpanded:
|
||||||
|
set_memory_size(Default);
|
||||||
|
break;
|
||||||
|
case StaticAnalyser::Vic20MemoryModel::EightKB:
|
||||||
|
set_memory_size(ThreeKB);
|
||||||
|
break;
|
||||||
|
case StaticAnalyser::Vic20MemoryModel::ThirtyTwoKB:
|
||||||
|
set_memory_size(ThirtyTwoKB);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_key_state(uint16_t key, bool isPressed) {
|
||||||
|
keyboard_via_->set_key_state(key, isPressed);
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear_all_keys() {
|
||||||
|
keyboard_via_->clear_all_keys();
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_joystick_state(JoystickInput input, bool isPressed) {
|
||||||
|
user_port_via_->set_joystick_state(input, isPressed);
|
||||||
|
keyboard_via_->set_joystick_state(input, isPressed);
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_memory_size(MemorySize size) {
|
||||||
memset(processor_read_memory_map_, 0, sizeof(processor_read_memory_map_));
|
memset(processor_read_memory_map_, 0, sizeof(processor_read_memory_map_));
|
||||||
memset(processor_write_memory_map_, 0, sizeof(processor_write_memory_map_));
|
memset(processor_write_memory_map_, 0, sizeof(processor_write_memory_map_));
|
||||||
|
|
||||||
@ -85,21 +334,32 @@ void Machine::set_memory_size(MemorySize size) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Machine::write_to_map(uint8_t **map, uint8_t *area, uint16_t address, uint16_t length) {
|
void set_region(Region region) {
|
||||||
address >>= 10;
|
region_ = region;
|
||||||
length >>= 10;
|
switch(region) {
|
||||||
while(length--) {
|
case PAL:
|
||||||
map[address] = area;
|
set_clock_rate(1108404);
|
||||||
area += 0x400;
|
if(mos6560_) {
|
||||||
address++;
|
mos6560_->set_output_mode(MOS::MOS6560<Commodore::Vic20::Vic6560>::OutputMode::PAL);
|
||||||
|
mos6560_->set_clock_rate(1108404);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case NTSC:
|
||||||
|
set_clock_rate(1022727);
|
||||||
|
if(mos6560_) {
|
||||||
|
mos6560_->set_output_mode(MOS::MOS6560<Commodore::Vic20::Vic6560>::OutputMode::NTSC);
|
||||||
|
mos6560_->set_clock_rate(1022727);
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Machine::~Machine() {
|
void set_use_fast_tape_hack(bool activate) {
|
||||||
delete[] rom_;
|
use_fast_tape_hack_ = activate;
|
||||||
}
|
}
|
||||||
|
|
||||||
Cycles Machine::perform_bus_operation(CPU::MOS6502::BusOperation operation, uint16_t address, uint8_t *value) {
|
// to satisfy CPU::MOS6502::Processor
|
||||||
|
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
|
// run the phase-1 part of this cycle, in which the VIC accesses memory
|
||||||
if(!is_running_at_zero_cost_) mos6560_->run_for(Cycles(1));
|
if(!is_running_at_zero_cost_) mos6560_->run_for(Cycles(1));
|
||||||
|
|
||||||
@ -195,40 +455,15 @@ Cycles Machine::perform_bus_operation(CPU::MOS6502::BusOperation operation, uint
|
|||||||
return Cycles(1);
|
return Cycles(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Machine::run_for(const Cycles cycles) {
|
void flush() {
|
||||||
|
mos6560_->flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
void run_for(const Cycles cycles) {
|
||||||
m6502_.run_for(cycles);
|
m6502_.run_for(cycles);
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark - 6522 delegate
|
void setup_output(float aspect_ratio) {
|
||||||
|
|
||||||
void Machine::mos6522_did_change_interrupt_status(void *mos6522) {
|
|
||||||
m6502_.set_nmi_line(user_port_via_->get_interrupt_line());
|
|
||||||
m6502_.set_irq_line(keyboard_via_->get_interrupt_line());
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - Setup
|
|
||||||
|
|
||||||
void Machine::set_region(Commodore::Vic20::Region region) {
|
|
||||||
region_ = region;
|
|
||||||
switch(region) {
|
|
||||||
case PAL:
|
|
||||||
set_clock_rate(1108404);
|
|
||||||
if(mos6560_) {
|
|
||||||
mos6560_->set_output_mode(MOS::MOS6560<Commodore::Vic20::Vic6560>::OutputMode::PAL);
|
|
||||||
mos6560_->set_clock_rate(1108404);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case NTSC:
|
|
||||||
set_clock_rate(1022727);
|
|
||||||
if(mos6560_) {
|
|
||||||
mos6560_->set_output_mode(MOS::MOS6560<Commodore::Vic20::Vic6560>::OutputMode::NTSC);
|
|
||||||
mos6560_->set_clock_rate(1022727);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Machine::setup_output(float aspect_ratio) {
|
|
||||||
mos6560_.reset(new Vic6560());
|
mos6560_.reset(new Vic6560());
|
||||||
mos6560_->get_speaker()->set_high_frequency_cut_off(1600); // There is a 1.6Khz low-pass filter in the Vic-20.
|
mos6560_->get_speaker()->set_high_frequency_cut_off(1600); // There is a 1.6Khz low-pass filter in the Vic-20.
|
||||||
set_region(region_);
|
set_region(region_);
|
||||||
@ -240,210 +475,91 @@ void Machine::setup_output(float aspect_ratio) {
|
|||||||
mos6560_->colour_memory = colour_memory_;
|
mos6560_->colour_memory = colour_memory_;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Machine::close_output() {
|
void close_output() {
|
||||||
mos6560_ = nullptr;
|
mos6560_ = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Machine::set_rom(ROMSlot slot, size_t length, const uint8_t *data) {
|
std::shared_ptr<Outputs::CRT::CRT> get_crt() {
|
||||||
uint8_t *target = nullptr;
|
return mos6560_->get_crt();
|
||||||
size_t max_length = 0x2000;
|
|
||||||
switch(slot) {
|
|
||||||
case Kernel: target = kernel_rom_; break;
|
|
||||||
case Characters: target = character_rom_; max_length = 0x1000; break;
|
|
||||||
case BASIC: target = basic_rom_; break;
|
|
||||||
case Drive:
|
|
||||||
drive_rom_.resize(length);
|
|
||||||
memcpy(drive_rom_.data(), data, length);
|
|
||||||
install_disk_rom();
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(target) {
|
std::shared_ptr<Outputs::Speaker> get_speaker() {
|
||||||
size_t length_to_copy = std::min(max_length, length);
|
return mos6560_->get_speaker();
|
||||||
memcpy(target, data, length_to_copy);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mar - Tape
|
void mos6522_did_change_interrupt_status(void *mos6522) {
|
||||||
|
m6502_.set_nmi_line(user_port_via_->get_interrupt_line());
|
||||||
void Machine::configure_as_target(const StaticAnalyser::Target &target) {
|
m6502_.set_irq_line(keyboard_via_->get_interrupt_line());
|
||||||
if(target.tapes.size()) {
|
|
||||||
tape_->set_tape(target.tapes.front());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(target.disks.size()) {
|
void set_typer_for_string(const char *string) {
|
||||||
// construct the 1540
|
|
||||||
c1540_.reset(new ::Commodore::C1540::Machine);
|
|
||||||
|
|
||||||
// attach it to the serial bus
|
|
||||||
c1540_->set_serial_bus(serial_bus_);
|
|
||||||
|
|
||||||
// hand it the disk
|
|
||||||
c1540_->set_disk(target.disks.front());
|
|
||||||
|
|
||||||
// install the ROM if it was previously set
|
|
||||||
install_disk_rom();
|
|
||||||
}
|
|
||||||
|
|
||||||
if(target.cartridges.size()) {
|
|
||||||
rom_address_ = 0xa000;
|
|
||||||
std::vector<uint8_t> rom_image = target.cartridges.front()->get_segments().front().data;
|
|
||||||
rom_length_ = (uint16_t)(rom_image.size());
|
|
||||||
|
|
||||||
rom_ = new uint8_t[0x2000];
|
|
||||||
memcpy(rom_, rom_image.data(), rom_image.size());
|
|
||||||
write_to_map(processor_read_memory_map_, rom_, rom_address_, 0x2000);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(target.loadingCommand.length()) {
|
|
||||||
set_typer_for_string(target.loadingCommand.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
switch(target.vic20.memory_model) {
|
|
||||||
case StaticAnalyser::Vic20MemoryModel::Unexpanded:
|
|
||||||
set_memory_size(Default);
|
|
||||||
break;
|
|
||||||
case StaticAnalyser::Vic20MemoryModel::EightKB:
|
|
||||||
set_memory_size(ThreeKB);
|
|
||||||
break;
|
|
||||||
case StaticAnalyser::Vic20MemoryModel::ThirtyTwoKB:
|
|
||||||
set_memory_size(ThirtyTwoKB);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Machine::set_typer_for_string(const char *string) {
|
|
||||||
std::unique_ptr<CharacterMapper> mapper(new CharacterMapper());
|
std::unique_ptr<CharacterMapper> mapper(new CharacterMapper());
|
||||||
Utility::TypeRecipient::set_typer_for_string(string, std::move(mapper));
|
Utility::TypeRecipient::set_typer_for_string(string, std::move(mapper));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Machine::tape_did_change_input(Storage::Tape::BinaryTapePlayer *tape) {
|
void tape_did_change_input(Storage::Tape::BinaryTapePlayer *tape) {
|
||||||
keyboard_via_->set_control_line_input(KeyboardVIA::Port::A, KeyboardVIA::Line::One, !tape->get_input());
|
keyboard_via_->set_control_line_input(KeyboardVIA::Port::A, KeyboardVIA::Line::One, !tape->get_input());
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark - Disc
|
private:
|
||||||
|
CPU::MOS6502::Processor<ConcreteMachine> m6502_;
|
||||||
|
|
||||||
void Machine::install_disk_rom() {
|
uint8_t character_rom_[0x1000];
|
||||||
|
uint8_t basic_rom_[0x2000];
|
||||||
|
uint8_t kernel_rom_[0x2000];
|
||||||
|
uint8_t expansion_ram_[0x8000];
|
||||||
|
|
||||||
|
uint8_t *rom_;
|
||||||
|
uint16_t rom_address_, rom_length_;
|
||||||
|
|
||||||
|
uint8_t user_basic_memory_[0x0400];
|
||||||
|
uint8_t screen_memory_[0x1000];
|
||||||
|
uint8_t colour_memory_[0x0400];
|
||||||
|
std::vector<uint8_t> drive_rom_;
|
||||||
|
|
||||||
|
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++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Region region_;
|
||||||
|
|
||||||
|
std::unique_ptr<Vic6560> mos6560_;
|
||||||
|
std::shared_ptr<UserPortVIA> user_port_via_;
|
||||||
|
std::shared_ptr<KeyboardVIA> keyboard_via_;
|
||||||
|
std::shared_ptr<SerialPort> serial_port_;
|
||||||
|
std::shared_ptr<::Commodore::Serial::Bus> serial_bus_;
|
||||||
|
|
||||||
|
// Tape
|
||||||
|
std::shared_ptr<Storage::Tape::BinaryTapePlayer> tape_;
|
||||||
|
bool use_fast_tape_hack_;
|
||||||
|
bool is_running_at_zero_cost_;
|
||||||
|
|
||||||
|
// Disk
|
||||||
|
std::shared_ptr<::Commodore::C1540::Machine> c1540_;
|
||||||
|
void install_disk_rom() {
|
||||||
if(!drive_rom_.empty() && c1540_) {
|
if(!drive_rom_.empty() && c1540_) {
|
||||||
c1540_->set_rom(drive_rom_);
|
c1540_->set_rom(drive_rom_);
|
||||||
c1540_->run_for(Cycles(2000000));
|
c1540_->run_for(Cycles(2000000));
|
||||||
drive_rom_.clear();
|
drive_rom_.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
#pragma mark - UserPortVIA
|
|
||||||
|
|
||||||
uint8_t UserPortVIA::get_port_input(Port port) {
|
|
||||||
if(!port) {
|
|
||||||
return port_a_ | (tape_->has_tape() ? 0x00 : 0x40);
|
|
||||||
}
|
|
||||||
return 0xff;
|
|
||||||
}
|
|
||||||
|
|
||||||
void UserPortVIA::set_control_line_output(Port port, Line line, bool value) {
|
|
||||||
if(port == Port::A && line == Line::Two) {
|
|
||||||
tape_->set_motor_control(!value);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void UserPortVIA::set_serial_line_state(::Commodore::Serial::Line line, bool value) {
|
using namespace Commodore::Vic20;
|
||||||
switch(line) {
|
|
||||||
default: break;
|
Machine *Machine::Vic20() {
|
||||||
case ::Commodore::Serial::Line::Data: port_a_ = (port_a_ & ~0x02) | (value ? 0x02 : 0x00); break;
|
return new Vic20::ConcreteMachine;
|
||||||
case ::Commodore::Serial::Line::Clock: port_a_ = (port_a_ & ~0x01) | (value ? 0x01 : 0x00); break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void UserPortVIA::set_joystick_state(JoystickInput input, bool value) {
|
Machine::~Machine() {}
|
||||||
if(input != JoystickInput::Right) {
|
|
||||||
port_a_ = (port_a_ & ~input) | (value ? 0 : input);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void UserPortVIA::set_port_output(Port port, uint8_t value, uint8_t mask) {
|
|
||||||
// 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));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
UserPortVIA::UserPortVIA() : port_a_(0xbf) {}
|
|
||||||
|
|
||||||
void UserPortVIA::set_serial_port(std::shared_ptr<::Commodore::Serial::Port> serialPort) {
|
|
||||||
serial_port_ = serialPort;
|
|
||||||
}
|
|
||||||
|
|
||||||
void UserPortVIA::set_tape(std::shared_ptr<Storage::Tape::BinaryTapePlayer> tape) {
|
|
||||||
tape_ = tape;
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - KeyboardVIA
|
|
||||||
|
|
||||||
KeyboardVIA::KeyboardVIA() : port_b_(0xff) {
|
|
||||||
clear_all_keys();
|
|
||||||
}
|
|
||||||
|
|
||||||
void KeyboardVIA::set_key_state(uint16_t key, bool isPressed) {
|
|
||||||
if(isPressed)
|
|
||||||
columns_[key & 7] &= ~(key >> 3);
|
|
||||||
else
|
|
||||||
columns_[key & 7] |= (key >> 3);
|
|
||||||
}
|
|
||||||
|
|
||||||
void KeyboardVIA::clear_all_keys() {
|
|
||||||
memset(columns_, 0xff, sizeof(columns_));
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t KeyboardVIA::get_port_input(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;
|
|
||||||
}
|
|
||||||
|
|
||||||
return port_b_;
|
|
||||||
}
|
|
||||||
|
|
||||||
void KeyboardVIA::set_port_output(Port port, uint8_t value, uint8_t mask) {
|
|
||||||
if(port)
|
|
||||||
activation_mask_ = (value & mask) | (~mask);
|
|
||||||
}
|
|
||||||
|
|
||||||
void KeyboardVIA::set_control_line_output(Port port, Line line, bool value) {
|
|
||||||
if(line == 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 == 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void KeyboardVIA::set_joystick_state(JoystickInput input, bool value) {
|
|
||||||
if(input == JoystickInput::Right) {
|
|
||||||
port_b_ = (port_b_ & ~input) | (value ? 0 : input);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void KeyboardVIA::set_serial_port(std::shared_ptr<::Commodore::Serial::Port> serialPort) {
|
|
||||||
serial_port_ = serialPort;
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - SerialPort
|
|
||||||
|
|
||||||
void SerialPort::set_input(::Commodore::Serial::Line line, ::Commodore::Serial::LineLevel level) {
|
|
||||||
std::shared_ptr<UserPortVIA> userPortVIA = user_port_via_.lock();
|
|
||||||
if(userPortVIA) userPortVIA->set_serial_line_state(line, (bool)level);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SerialPort::set_user_port_via(std::shared_ptr<UserPortVIA> userPortVIA) {
|
|
||||||
user_port_via_ = userPortVIA;
|
|
||||||
}
|
|
||||||
|
@ -13,15 +13,7 @@
|
|||||||
#include "../../CRTMachine.hpp"
|
#include "../../CRTMachine.hpp"
|
||||||
#include "../../Typer.hpp"
|
#include "../../Typer.hpp"
|
||||||
|
|
||||||
#include "../../../Processors/6502/6502.hpp"
|
#include <cstdint>
|
||||||
#include "../../../Components/6560/6560.hpp"
|
|
||||||
#include "../../../Components/6522/6522.hpp"
|
|
||||||
|
|
||||||
#include "../SerialBus.hpp"
|
|
||||||
#include "../1540/C1540.hpp"
|
|
||||||
|
|
||||||
#include "../../../Storage/Tape/Tape.hpp"
|
|
||||||
#include "../../../Storage/Disk/Disk.hpp"
|
|
||||||
|
|
||||||
namespace Commodore {
|
namespace Commodore {
|
||||||
namespace Vic20 {
|
namespace Vic20 {
|
||||||
@ -44,9 +36,8 @@ enum Region {
|
|||||||
PAL
|
PAL
|
||||||
};
|
};
|
||||||
|
|
||||||
#define key(line, mask) (((mask) << 3) | (line))
|
|
||||||
|
|
||||||
enum Key: uint16_t {
|
enum Key: uint16_t {
|
||||||
|
#define key(line, mask) (((mask) << 3) | (line))
|
||||||
Key2 = key(7, 0x01), Key4 = key(7, 0x02), Key6 = key(7, 0x04), Key8 = key(7, 0x08),
|
Key2 = key(7, 0x01), Key4 = key(7, 0x02), Key6 = key(7, 0x04), Key8 = key(7, 0x08),
|
||||||
Key0 = key(7, 0x10), KeyDash = key(7, 0x20), KeyHome = key(7, 0x40), KeyF7 = key(7, 0x80),
|
Key0 = key(7, 0x10), KeyDash = key(7, 0x20), KeyHome = key(7, 0x40), KeyF7 = key(7, 0x80),
|
||||||
KeyQ = key(6, 0x01), KeyE = key(6, 0x02), KeyT = key(6, 0x04), KeyU = key(6, 0x08),
|
KeyQ = key(6, 0x01), KeyE = key(6, 0x02), KeyT = key(6, 0x04), KeyU = key(6, 0x08),
|
||||||
@ -63,6 +54,7 @@ enum Key: uint16_t {
|
|||||||
KeyI = key(1, 0x10), KeyP = key(1, 0x20), KeyAsterisk = key(1, 0x40), KeyReturn = key(1, 0x80),
|
KeyI = key(1, 0x10), KeyP = key(1, 0x20), KeyAsterisk = key(1, 0x40), KeyReturn = key(1, 0x80),
|
||||||
Key1 = key(0, 0x01), Key3 = key(0, 0x02), Key5 = key(0, 0x04), Key7 = key(0, 0x08),
|
Key1 = key(0, 0x01), Key3 = key(0, 0x02), Key5 = key(0, 0x04), Key7 = key(0, 0x08),
|
||||||
Key9 = key(0, 0x10), KeyPlus = key(0, 0x20), KeyGBP = key(0, 0x40), KeyDelete = key(0, 0x80),
|
Key9 = key(0, 0x10), KeyPlus = key(0, 0x20), KeyGBP = key(0, 0x40), KeyDelete = key(0, 0x80),
|
||||||
|
#undef key
|
||||||
};
|
};
|
||||||
|
|
||||||
enum JoystickInput {
|
enum JoystickInput {
|
||||||
@ -73,155 +65,23 @@ enum JoystickInput {
|
|||||||
Fire = 0x20
|
Fire = 0x20
|
||||||
};
|
};
|
||||||
|
|
||||||
class UserPortVIA: public MOS::MOS6522<UserPortVIA>, public MOS::MOS6522IRQDelegate {
|
|
||||||
public:
|
|
||||||
UserPortVIA();
|
|
||||||
using MOS6522IRQDelegate::set_interrupt_status;
|
|
||||||
|
|
||||||
uint8_t get_port_input(Port port);
|
|
||||||
void set_control_line_output(Port port, Line line, bool value);
|
|
||||||
void set_serial_line_state(::Commodore::Serial::Line line, bool value);
|
|
||||||
void set_joystick_state(JoystickInput input, bool value);
|
|
||||||
void set_port_output(Port port, uint8_t value, uint8_t mask);
|
|
||||||
|
|
||||||
void set_serial_port(std::shared_ptr<::Commodore::Serial::Port> serialPort);
|
|
||||||
void set_tape(std::shared_ptr<Storage::Tape::BinaryTapePlayer> tape);
|
|
||||||
|
|
||||||
private:
|
|
||||||
uint8_t port_a_;
|
|
||||||
std::weak_ptr<::Commodore::Serial::Port> serial_port_;
|
|
||||||
std::shared_ptr<Storage::Tape::BinaryTapePlayer> tape_;
|
|
||||||
};
|
|
||||||
|
|
||||||
class KeyboardVIA: public MOS::MOS6522<KeyboardVIA>, public MOS::MOS6522IRQDelegate {
|
|
||||||
public:
|
|
||||||
KeyboardVIA();
|
|
||||||
using MOS6522IRQDelegate::set_interrupt_status;
|
|
||||||
|
|
||||||
void set_key_state(uint16_t key, bool isPressed);
|
|
||||||
void clear_all_keys();
|
|
||||||
|
|
||||||
// to satisfy MOS::MOS6522
|
|
||||||
uint8_t get_port_input(Port port);
|
|
||||||
|
|
||||||
void set_port_output(Port port, uint8_t value, uint8_t mask);
|
|
||||||
void set_control_line_output(Port port, Line line, bool value);
|
|
||||||
|
|
||||||
void set_joystick_state(JoystickInput input, bool value);
|
|
||||||
|
|
||||||
void set_serial_port(std::shared_ptr<::Commodore::Serial::Port> serialPort);
|
|
||||||
|
|
||||||
private:
|
|
||||||
uint8_t port_b_;
|
|
||||||
uint8_t columns_[8];
|
|
||||||
uint8_t activation_mask_;
|
|
||||||
std::weak_ptr<::Commodore::Serial::Port> serial_port_;
|
|
||||||
};
|
|
||||||
|
|
||||||
class SerialPort : public ::Commodore::Serial::Port {
|
|
||||||
public:
|
|
||||||
void set_input(::Commodore::Serial::Line line, ::Commodore::Serial::LineLevel level);
|
|
||||||
void set_user_port_via(std::shared_ptr<UserPortVIA> userPortVIA);
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::weak_ptr<UserPortVIA> user_port_via_;
|
|
||||||
};
|
|
||||||
|
|
||||||
class Vic6560: public MOS::MOS6560<Vic6560> {
|
|
||||||
public:
|
|
||||||
inline 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];
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t *video_memory_map[16];
|
|
||||||
uint8_t *colour_memory;
|
|
||||||
};
|
|
||||||
|
|
||||||
class Machine:
|
class Machine:
|
||||||
public CPU::MOS6502::BusHandler,
|
public ConfigurationTarget::Machine,
|
||||||
public CRTMachine::Machine,
|
public CRTMachine::Machine,
|
||||||
public MOS::MOS6522IRQDelegate::Delegate,
|
public KeyboardMachine::Machine {
|
||||||
public Utility::TypeRecipient,
|
|
||||||
public Storage::Tape::BinaryTapePlayer::Delegate,
|
|
||||||
public ConfigurationTarget::Machine {
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Machine();
|
virtual ~Machine();
|
||||||
~Machine();
|
|
||||||
|
|
||||||
void set_rom(ROMSlot slot, size_t length, const uint8_t *data);
|
static Machine *Vic20();
|
||||||
void configure_as_target(const StaticAnalyser::Target &target);
|
|
||||||
|
|
||||||
void set_key_state(uint16_t key, bool isPressed) { keyboard_via_->set_key_state(key, isPressed); }
|
virtual void set_rom(ROMSlot slot, size_t length, const uint8_t *data) = 0;
|
||||||
void clear_all_keys() { keyboard_via_->clear_all_keys(); }
|
|
||||||
void set_joystick_state(JoystickInput input, bool isPressed) {
|
|
||||||
user_port_via_->set_joystick_state(input, isPressed);
|
|
||||||
keyboard_via_->set_joystick_state(input, isPressed);
|
|
||||||
}
|
|
||||||
|
|
||||||
void set_memory_size(MemorySize size);
|
virtual void set_joystick_state(JoystickInput input, bool isPressed) = 0;
|
||||||
void set_region(Region region);
|
|
||||||
|
|
||||||
inline void set_use_fast_tape_hack(bool activate) { use_fast_tape_hack_ = activate; }
|
virtual void set_memory_size(MemorySize size) = 0;
|
||||||
|
virtual void set_region(Region region) = 0;
|
||||||
|
|
||||||
// to satisfy CPU::MOS6502::Processor
|
virtual void set_use_fast_tape_hack(bool activate) = 0;
|
||||||
Cycles perform_bus_operation(CPU::MOS6502::BusOperation operation, uint16_t address, uint8_t *value);
|
|
||||||
void flush() { mos6560_->flush(); }
|
|
||||||
|
|
||||||
// to satisfy CRTMachine::Machine
|
|
||||||
virtual void setup_output(float aspect_ratio);
|
|
||||||
virtual void close_output();
|
|
||||||
virtual std::shared_ptr<Outputs::CRT::CRT> get_crt() { return mos6560_->get_crt(); }
|
|
||||||
virtual std::shared_ptr<Outputs::Speaker> get_speaker() { return mos6560_->get_speaker(); }
|
|
||||||
virtual void run_for(const Cycles cycles);
|
|
||||||
|
|
||||||
// to satisfy MOS::MOS6522::Delegate
|
|
||||||
virtual void mos6522_did_change_interrupt_status(void *mos6522);
|
|
||||||
|
|
||||||
// for Utility::TypeRecipient
|
|
||||||
uint16_t *sequence_for_character(Utility::Typer *typer, char character);
|
|
||||||
void set_typer_for_string(const char *string);
|
|
||||||
|
|
||||||
// for Tape::Delegate
|
|
||||||
virtual void tape_did_change_input(Storage::Tape::BinaryTapePlayer *tape);
|
|
||||||
|
|
||||||
private:
|
|
||||||
CPU::MOS6502::Processor<Machine> m6502_;
|
|
||||||
|
|
||||||
uint8_t character_rom_[0x1000];
|
|
||||||
uint8_t basic_rom_[0x2000];
|
|
||||||
uint8_t kernel_rom_[0x2000];
|
|
||||||
uint8_t expansion_ram_[0x8000];
|
|
||||||
|
|
||||||
uint8_t *rom_;
|
|
||||||
uint16_t rom_address_, rom_length_;
|
|
||||||
|
|
||||||
uint8_t user_basic_memory_[0x0400];
|
|
||||||
uint8_t screen_memory_[0x1000];
|
|
||||||
uint8_t colour_memory_[0x0400];
|
|
||||||
std::vector<uint8_t> drive_rom_;
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
Region region_;
|
|
||||||
|
|
||||||
std::unique_ptr<Vic6560> mos6560_;
|
|
||||||
std::shared_ptr<UserPortVIA> user_port_via_;
|
|
||||||
std::shared_ptr<KeyboardVIA> keyboard_via_;
|
|
||||||
std::shared_ptr<SerialPort> serial_port_;
|
|
||||||
std::shared_ptr<::Commodore::Serial::Bus> serial_bus_;
|
|
||||||
|
|
||||||
// Tape
|
|
||||||
std::shared_ptr<Storage::Tape::BinaryTapePlayer> tape_;
|
|
||||||
bool use_fast_tape_hack_;
|
|
||||||
bool is_running_at_zero_cost_;
|
|
||||||
|
|
||||||
// Disk
|
|
||||||
std::shared_ptr<::Commodore::C1540::Machine> c1540_;
|
|
||||||
void install_disk_rom();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -18,17 +18,21 @@
|
|||||||
using namespace Commodore::Vic20;
|
using namespace Commodore::Vic20;
|
||||||
|
|
||||||
@implementation CSVic20 {
|
@implementation CSVic20 {
|
||||||
Machine _vic20;
|
std::unique_ptr<Machine> _vic20;
|
||||||
BOOL _joystickMode;
|
BOOL _joystickMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CRTMachine::Machine * const)machine { return &_vic20; }
|
- (CRTMachine::Machine * const)machine {
|
||||||
|
if(!_vic20) {
|
||||||
|
_vic20.reset(Commodore::Vic20::Machine::Vic20());
|
||||||
|
}
|
||||||
|
return _vic20.get();
|
||||||
|
}
|
||||||
- (NSString *)userDefaultsPrefix { return @"vic20"; }
|
- (NSString *)userDefaultsPrefix { return @"vic20"; }
|
||||||
|
|
||||||
- (instancetype)init {
|
- (instancetype)init {
|
||||||
self = [super init];
|
self = [super init];
|
||||||
if(self)
|
if(self) {
|
||||||
{
|
|
||||||
[self setDriveROM:[[NSBundle mainBundle] dataForResource:@"1540" withExtension:@"bin" subdirectory:@"ROMImages/Commodore1540"]];
|
[self setDriveROM:[[NSBundle mainBundle] dataForResource:@"1540" withExtension:@"bin" subdirectory:@"ROMImages/Commodore1540"]];
|
||||||
[self setBASICROM:[self rom:@"basic"]];
|
[self setBASICROM:[self rom:@"basic"]];
|
||||||
[self setCountry:CSVic20CountryEuropean];
|
[self setCountry:CSVic20CountryEuropean];
|
||||||
@ -36,8 +40,7 @@ using namespace Commodore::Vic20;
|
|||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSData *)rom:(NSString *)name
|
- (NSData *)rom:(NSString *)name {
|
||||||
{
|
|
||||||
return [[NSBundle mainBundle] dataForResource:name withExtension:@"bin" subdirectory:@"ROMImages/Vic20"];
|
return [[NSBundle mainBundle] dataForResource:name withExtension:@"bin" subdirectory:@"ROMImages/Vic20"];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -45,7 +48,7 @@ using namespace Commodore::Vic20;
|
|||||||
|
|
||||||
- (void)setROM:(nonnull NSData *)rom slot:(ROMSlot)slot {
|
- (void)setROM:(nonnull NSData *)rom slot:(ROMSlot)slot {
|
||||||
@synchronized(self) {
|
@synchronized(self) {
|
||||||
_vic20.set_rom(slot, rom.length, (const uint8_t *)rom.bytes);
|
_vic20->set_rom(slot, rom.length, (const uint8_t *)rom.bytes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -120,32 +123,26 @@ using namespace Commodore::Vic20;
|
|||||||
// KeyPlus
|
// KeyPlus
|
||||||
// KeyGBP
|
// KeyGBP
|
||||||
|
|
||||||
if(key == VK_Tab && isPressed)
|
if(key == VK_Tab && isPressed) {
|
||||||
{
|
|
||||||
_joystickMode ^= YES;
|
_joystickMode ^= YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
@synchronized(self) {
|
@synchronized(self) {
|
||||||
if(_joystickMode)
|
if(_joystickMode) {
|
||||||
{
|
switch(key) {
|
||||||
switch(key)
|
case VK_UpArrow: _vic20->set_joystick_state(JoystickInput::Up, isPressed); break;
|
||||||
{
|
case VK_DownArrow: _vic20->set_joystick_state(JoystickInput::Down, isPressed); break;
|
||||||
case VK_UpArrow: _vic20.set_joystick_state(JoystickInput::Up, isPressed); break;
|
case VK_LeftArrow: _vic20->set_joystick_state(JoystickInput::Left, isPressed); break;
|
||||||
case VK_DownArrow: _vic20.set_joystick_state(JoystickInput::Down, isPressed); break;
|
case VK_RightArrow: _vic20->set_joystick_state(JoystickInput::Right, isPressed); break;
|
||||||
case VK_LeftArrow: _vic20.set_joystick_state(JoystickInput::Left, isPressed); break;
|
case VK_ANSI_A: _vic20->set_joystick_state(JoystickInput::Fire, isPressed); break;
|
||||||
case VK_RightArrow: _vic20.set_joystick_state(JoystickInput::Right, isPressed); break;
|
|
||||||
case VK_ANSI_A: _vic20.set_joystick_state(JoystickInput::Fire, isPressed); break;
|
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else
|
switch(key) {
|
||||||
{
|
|
||||||
switch(key)
|
|
||||||
{
|
|
||||||
default: {
|
default: {
|
||||||
NSNumber *targetKey = vicKeysByKeys[@(key)];
|
NSNumber *targetKey = vicKeysByKeys[@(key)];
|
||||||
if(targetKey)
|
if(targetKey)
|
||||||
{
|
{
|
||||||
_vic20.set_key_state((Key)targetKey.integerValue, isPressed);
|
_vic20->set_key_state((Key)targetKey.integerValue, isPressed);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -155,8 +152,8 @@ using namespace Commodore::Vic20;
|
|||||||
|
|
||||||
case VK_Shift:
|
case VK_Shift:
|
||||||
// Yuck
|
// Yuck
|
||||||
_vic20.set_key_state(Key::KeyLShift, isPressed);
|
_vic20->set_key_state(Key::KeyLShift, isPressed);
|
||||||
_vic20.set_key_state(Key::KeyRShift, isPressed);
|
_vic20->set_key_state(Key::KeyRShift, isPressed);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -165,7 +162,7 @@ using namespace Commodore::Vic20;
|
|||||||
|
|
||||||
- (void)clearAllKeys {
|
- (void)clearAllKeys {
|
||||||
@synchronized(self) {
|
@synchronized(self) {
|
||||||
_vic20.clear_all_keys();
|
_vic20->clear_all_keys();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -174,7 +171,7 @@ using namespace Commodore::Vic20;
|
|||||||
- (void)setUseFastLoadingHack:(BOOL)useFastLoadingHack {
|
- (void)setUseFastLoadingHack:(BOOL)useFastLoadingHack {
|
||||||
_useFastLoadingHack = useFastLoadingHack;
|
_useFastLoadingHack = useFastLoadingHack;
|
||||||
@synchronized(self) {
|
@synchronized(self) {
|
||||||
_vic20.set_use_fast_tape_hack(useFastLoadingHack ? true : false);
|
_vic20->set_use_fast_tape_hack(useFastLoadingHack ? true : false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -182,8 +179,7 @@ using namespace Commodore::Vic20;
|
|||||||
_country = country;
|
_country = country;
|
||||||
NSString *charactersROM, *kernelROM;
|
NSString *charactersROM, *kernelROM;
|
||||||
Commodore::Vic20::Region region;
|
Commodore::Vic20::Region region;
|
||||||
switch(country)
|
switch(country) {
|
||||||
{
|
|
||||||
case CSVic20CountryDanish:
|
case CSVic20CountryDanish:
|
||||||
region = Commodore::Vic20::Region::PAL;
|
region = Commodore::Vic20::Region::PAL;
|
||||||
charactersROM = @"characters-danish";
|
charactersROM = @"characters-danish";
|
||||||
@ -212,7 +208,7 @@ using namespace Commodore::Vic20;
|
|||||||
}
|
}
|
||||||
|
|
||||||
@synchronized(self) {
|
@synchronized(self) {
|
||||||
_vic20.set_region(region);
|
_vic20->set_region(region);
|
||||||
[self setCharactersROM:[self rom:charactersROM]];
|
[self setCharactersROM:[self rom:charactersROM]];
|
||||||
[self setKernelROM:[self rom:kernelROM]];
|
[self setKernelROM:[self rom:kernelROM]];
|
||||||
}
|
}
|
||||||
@ -222,9 +218,9 @@ using namespace Commodore::Vic20;
|
|||||||
_memorySize = memorySize;
|
_memorySize = memorySize;
|
||||||
@synchronized(self) {
|
@synchronized(self) {
|
||||||
switch(memorySize) {
|
switch(memorySize) {
|
||||||
case CSVic20MemorySize5Kb: _vic20.set_memory_size(Commodore::Vic20::Default); break;
|
case CSVic20MemorySize5Kb: _vic20->set_memory_size(Commodore::Vic20::Default); break;
|
||||||
case CSVic20MemorySize8Kb: _vic20.set_memory_size(Commodore::Vic20::ThreeKB); break;
|
case CSVic20MemorySize8Kb: _vic20->set_memory_size(Commodore::Vic20::ThreeKB); break;
|
||||||
case CSVic20MemorySize32Kb: _vic20.set_memory_size(Commodore::Vic20::ThirtyTwoKB); break;
|
case CSVic20MemorySize32Kb: _vic20->set_memory_size(Commodore::Vic20::ThirtyTwoKB); break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user