mirror of
https://github.com/TomHarte/CLK.git
synced 2024-12-25 18:30:21 +00:00
Merge pull request #201 from TomHarte/OricInline
Hides the Oric implementation innards
This commit is contained in:
commit
b7e0f64892
@ -8,287 +8,372 @@
|
||||
|
||||
#include "Oric.hpp"
|
||||
|
||||
#include "Video.hpp"
|
||||
#include "Microdisc.hpp"
|
||||
#include "CharacterMapper.hpp"
|
||||
#include "../MemoryFuzzer.hpp"
|
||||
|
||||
#include "../MemoryFuzzer.hpp"
|
||||
#include "../Typer.hpp"
|
||||
|
||||
#include "../../Processors/6502/6502.hpp"
|
||||
#include "../../Components/6522/6522.hpp"
|
||||
#include "../../Components/AY38910/AY38910.hpp"
|
||||
|
||||
#include "../../Storage/Tape/Tape.hpp"
|
||||
#include "../../Storage/Tape/Parsers/Oric.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
namespace Oric {
|
||||
|
||||
class ConcreteMachine:
|
||||
public CPU::MOS6502::BusHandler,
|
||||
public MOS::MOS6522IRQDelegate::Delegate,
|
||||
public Utility::TypeRecipient,
|
||||
public Storage::Tape::BinaryTapePlayer::Delegate,
|
||||
public Microdisc::Delegate,
|
||||
public Machine {
|
||||
|
||||
public:
|
||||
ConcreteMachine() :
|
||||
m6502_(*this),
|
||||
use_fast_tape_hack_(false),
|
||||
typer_delay_(2500000),
|
||||
keyboard_read_count_(0),
|
||||
keyboard_(new Keyboard),
|
||||
ram_top_(0xbfff),
|
||||
paged_rom_(rom_),
|
||||
microdisc_is_enabled_(false) {
|
||||
set_clock_rate(1000000);
|
||||
via_.set_interrupt_delegate(this);
|
||||
via_.keyboard = keyboard_;
|
||||
clear_all_keys();
|
||||
via_.tape->set_delegate(this);
|
||||
Memory::Fuzz(ram_, sizeof(ram_));
|
||||
}
|
||||
|
||||
void set_rom(ROM rom, const std::vector<uint8_t> &data) {
|
||||
switch(rom) {
|
||||
case BASIC11: basic11_rom_ = std::move(data); break;
|
||||
case BASIC10: basic10_rom_ = std::move(data); break;
|
||||
case Microdisc: microdisc_rom_ = std::move(data); break;
|
||||
case Colour:
|
||||
colour_rom_ = std::move(data);
|
||||
if(video_output_) video_output_->set_colour_rom(colour_rom_);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void set_key_state(uint16_t key, bool isPressed) {
|
||||
if(key == KeyNMI) {
|
||||
m6502_.set_nmi_line(isPressed);
|
||||
} else {
|
||||
if(isPressed)
|
||||
keyboard_->rows[key >> 8] |= (key & 0xff);
|
||||
else
|
||||
keyboard_->rows[key >> 8] &= ~(key & 0xff);
|
||||
}
|
||||
}
|
||||
|
||||
void clear_all_keys() {
|
||||
memset(keyboard_->rows, 0, sizeof(keyboard_->rows));
|
||||
}
|
||||
|
||||
void set_use_fast_tape_hack(bool activate) {
|
||||
use_fast_tape_hack_ = activate;
|
||||
}
|
||||
|
||||
void set_output_device(Outputs::CRT::OutputDevice output_device) {
|
||||
video_output_->set_output_device(output_device);
|
||||
}
|
||||
|
||||
// to satisfy ConfigurationTarget::Machine
|
||||
void configure_as_target(const StaticAnalyser::Target &target) {
|
||||
if(target.tapes.size()) {
|
||||
via_.tape->set_tape(target.tapes.front());
|
||||
}
|
||||
|
||||
if(target.loadingCommand.length()) {
|
||||
set_typer_for_string(target.loadingCommand.c_str());
|
||||
}
|
||||
|
||||
if(target.oric.has_microdisc) {
|
||||
microdisc_is_enabled_ = true;
|
||||
microdisc_did_change_paging_flags(µdisc_);
|
||||
microdisc_.set_delegate(this);
|
||||
}
|
||||
|
||||
int drive_index = 0;
|
||||
for(auto disk : target.disks) {
|
||||
if(drive_index < 4) microdisc_.set_disk(disk, drive_index);
|
||||
drive_index++;
|
||||
}
|
||||
|
||||
if(target.oric.use_atmos_rom) {
|
||||
memcpy(rom_, basic11_rom_.data(), std::min(basic11_rom_.size(), sizeof(rom_)));
|
||||
|
||||
is_using_basic11_ = true;
|
||||
tape_get_byte_address_ = 0xe6c9;
|
||||
scan_keyboard_address_ = 0xf495;
|
||||
tape_speed_address_ = 0x024d;
|
||||
} else {
|
||||
memcpy(rom_, basic10_rom_.data(), std::min(basic10_rom_.size(), sizeof(rom_)));
|
||||
|
||||
is_using_basic11_ = false;
|
||||
tape_get_byte_address_ = 0xe630;
|
||||
scan_keyboard_address_ = 0xf43c;
|
||||
tape_speed_address_ = 0x67;
|
||||
}
|
||||
}
|
||||
|
||||
// to satisfy CPU::MOS6502::BusHandler
|
||||
Cycles perform_bus_operation(CPU::MOS6502::BusOperation operation, uint16_t address, uint8_t *value) {
|
||||
if(address > ram_top_) {
|
||||
if(isReadOperation(operation)) *value = paged_rom_[address - ram_top_ - 1];
|
||||
|
||||
// 024D = 0 => fast; otherwise slow
|
||||
// E6C9 = read byte: return byte in A
|
||||
if(address == tape_get_byte_address_ && paged_rom_ == rom_ && use_fast_tape_hack_ && operation == CPU::MOS6502::BusOperation::ReadOpcode && via_.tape->has_tape() && !via_.tape->get_tape()->is_at_end()) {
|
||||
uint8_t next_byte = via_.tape->get_next_byte(!ram_[tape_speed_address_]);
|
||||
m6502_.set_value_of_register(CPU::MOS6502::A, next_byte);
|
||||
m6502_.set_value_of_register(CPU::MOS6502::Flags, next_byte ? 0 : CPU::MOS6502::Flag::Zero);
|
||||
*value = 0x60; // i.e. RTS
|
||||
}
|
||||
} else {
|
||||
if((address & 0xff00) == 0x0300) {
|
||||
if(microdisc_is_enabled_ && address >= 0x0310) {
|
||||
switch(address) {
|
||||
case 0x0310: case 0x0311: case 0x0312: case 0x0313:
|
||||
if(isReadOperation(operation)) *value = microdisc_.get_register(address);
|
||||
else microdisc_.set_register(address, *value);
|
||||
break;
|
||||
case 0x314: case 0x315: case 0x316: case 0x317:
|
||||
if(isReadOperation(operation)) *value = microdisc_.get_interrupt_request_register();
|
||||
else microdisc_.set_control_register(*value);
|
||||
break;
|
||||
case 0x318: case 0x319: case 0x31a: case 0x31b:
|
||||
if(isReadOperation(operation)) *value = microdisc_.get_data_request_register();
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if(isReadOperation(operation)) *value = via_.get_register(address);
|
||||
else via_.set_register(address, *value);
|
||||
}
|
||||
} else {
|
||||
if(isReadOperation(operation))
|
||||
*value = ram_[address];
|
||||
else {
|
||||
if(address >= 0x9800 && address <= 0xc000) { update_video(); typer_delay_ = 0; }
|
||||
ram_[address] = *value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(typer_ && address == scan_keyboard_address_ && operation == CPU::MOS6502::BusOperation::ReadOpcode) {
|
||||
// the Oric 1 misses any key pressed on the very first entry into the read keyboard routine, so don't
|
||||
// do anything until at least the second, regardless of machine
|
||||
if(!keyboard_read_count_) keyboard_read_count_++;
|
||||
else if(!typer_->type_next_character()) {
|
||||
clear_all_keys();
|
||||
typer_.reset();
|
||||
}
|
||||
}
|
||||
|
||||
via_.run_for(Cycles(1));
|
||||
if(microdisc_is_enabled_) microdisc_.run_for(Cycles(8));
|
||||
cycles_since_video_update_++;
|
||||
return Cycles(1);
|
||||
}
|
||||
|
||||
void flush() {
|
||||
update_video();
|
||||
via_.flush();
|
||||
}
|
||||
|
||||
// to satisfy CRTMachine::Machine
|
||||
void setup_output(float aspect_ratio) {
|
||||
via_.ay8910.reset(new GI::AY38910::AY38910());
|
||||
via_.ay8910->set_clock_rate(1000000);
|
||||
video_output_.reset(new VideoOutput(ram_));
|
||||
if(!colour_rom_.empty()) video_output_->set_colour_rom(colour_rom_);
|
||||
}
|
||||
|
||||
void close_output() {
|
||||
video_output_.reset();
|
||||
via_.ay8910.reset();
|
||||
}
|
||||
|
||||
std::shared_ptr<Outputs::CRT::CRT> get_crt() {
|
||||
return video_output_->get_crt();
|
||||
}
|
||||
|
||||
std::shared_ptr<Outputs::Speaker> get_speaker() {
|
||||
return via_.ay8910;
|
||||
}
|
||||
|
||||
void run_for(const Cycles cycles) {
|
||||
m6502_.run_for(cycles);
|
||||
}
|
||||
|
||||
// to satisfy MOS::MOS6522IRQDelegate::Delegate
|
||||
void mos6522_did_change_interrupt_status(void *mos6522) {
|
||||
set_interrupt_line();
|
||||
}
|
||||
|
||||
// to satisfy Storage::Tape::BinaryTapePlayer::Delegate
|
||||
void tape_did_change_input(Storage::Tape::BinaryTapePlayer *tape_player) {
|
||||
// set CB1
|
||||
via_.set_control_line_input(VIA::Port::B, VIA::Line::One, !tape_player->get_input());
|
||||
}
|
||||
|
||||
// for Utility::TypeRecipient::Delegate
|
||||
void set_typer_for_string(const char *string) {
|
||||
std::unique_ptr<CharacterMapper> mapper(new CharacterMapper);
|
||||
Utility::TypeRecipient::set_typer_for_string(string, std::move(mapper));
|
||||
}
|
||||
|
||||
// for Microdisc::Delegate
|
||||
void microdisc_did_change_paging_flags(class Microdisc *microdisc) {
|
||||
int flags = microdisc->get_paging_flags();
|
||||
if(!(flags&Microdisc::PagingFlags::BASICDisable)) {
|
||||
ram_top_ = 0xbfff;
|
||||
paged_rom_ = rom_;
|
||||
} else {
|
||||
if(flags&Microdisc::PagingFlags::MicrodscDisable) {
|
||||
ram_top_ = 0xffff;
|
||||
} else {
|
||||
ram_top_ = 0xdfff;
|
||||
paged_rom_ = microdisc_rom_.data();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void wd1770_did_change_output(WD::WD1770 *wd1770) {
|
||||
set_interrupt_line();
|
||||
}
|
||||
|
||||
private:
|
||||
CPU::MOS6502::Processor<ConcreteMachine> m6502_;
|
||||
|
||||
// RAM and ROM
|
||||
std::vector<uint8_t> basic11_rom_, basic10_rom_, microdisc_rom_, colour_rom_;
|
||||
uint8_t ram_[65536], rom_[16384];
|
||||
Cycles cycles_since_video_update_;
|
||||
inline void update_video() {
|
||||
video_output_->run_for(cycles_since_video_update_.flush());
|
||||
}
|
||||
|
||||
// ROM bookkeeping
|
||||
bool is_using_basic11_;
|
||||
uint16_t tape_get_byte_address_, scan_keyboard_address_, tape_speed_address_;
|
||||
int keyboard_read_count_;
|
||||
|
||||
// Outputs
|
||||
std::unique_ptr<VideoOutput> video_output_;
|
||||
|
||||
// Keyboard
|
||||
class Keyboard {
|
||||
public:
|
||||
uint8_t row;
|
||||
uint8_t rows[8];
|
||||
};
|
||||
int typer_delay_;
|
||||
|
||||
// The tape
|
||||
class TapePlayer: public Storage::Tape::BinaryTapePlayer {
|
||||
public:
|
||||
TapePlayer() : Storage::Tape::BinaryTapePlayer(1000000) {}
|
||||
|
||||
uint8_t get_next_byte(bool fast) {
|
||||
return (uint8_t)parser_.get_next_byte(get_tape(), fast);
|
||||
}
|
||||
|
||||
private:
|
||||
Storage::Tape::Oric::Parser parser_;
|
||||
};
|
||||
bool use_fast_tape_hack_;
|
||||
|
||||
// VIA (which owns the tape and the AY)
|
||||
class VIA: public MOS::MOS6522<VIA>, public MOS::MOS6522IRQDelegate {
|
||||
public:
|
||||
VIA() :
|
||||
MOS::MOS6522<VIA>(),
|
||||
tape(new TapePlayer) {}
|
||||
|
||||
using MOS6522IRQDelegate::set_interrupt_status;
|
||||
|
||||
void set_control_line_output(Port port, Line line, bool value) {
|
||||
if(line) {
|
||||
if(port) ay_bdir_ = value; else ay_bc1_ = value;
|
||||
update_ay();
|
||||
}
|
||||
}
|
||||
|
||||
void set_port_output(Port port, uint8_t value, uint8_t direction_mask) {
|
||||
if(port) {
|
||||
keyboard->row = value;
|
||||
tape->set_motor_control(value & 0x40);
|
||||
} else {
|
||||
ay8910->set_data_input(value);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t get_port_input(Port port) {
|
||||
if(port) {
|
||||
uint8_t column = ay8910->get_port_output(false) ^ 0xff;
|
||||
return (keyboard->rows[keyboard->row & 7] & column) ? 0x08 : 0x00;
|
||||
} else {
|
||||
return ay8910->get_data_output();
|
||||
}
|
||||
}
|
||||
|
||||
inline void run_for(const Cycles cycles) {
|
||||
cycles_since_ay_update_ += cycles;
|
||||
MOS::MOS6522<VIA>::run_for(cycles);
|
||||
tape->run_for(cycles);
|
||||
}
|
||||
|
||||
void flush() {
|
||||
ay8910->run_for(cycles_since_ay_update_.flush());
|
||||
ay8910->flush();
|
||||
}
|
||||
|
||||
std::shared_ptr<GI::AY38910::AY38910> ay8910;
|
||||
std::unique_ptr<TapePlayer> tape;
|
||||
std::shared_ptr<Keyboard> keyboard;
|
||||
|
||||
private:
|
||||
void update_ay() {
|
||||
ay8910->run_for(cycles_since_ay_update_.flush());
|
||||
ay8910->set_control_lines( (GI::AY38910::ControlLines)((ay_bdir_ ? GI::AY38910::BDIR : 0) | (ay_bc1_ ? GI::AY38910::BC1 : 0) | GI::AY38910::BC2));
|
||||
}
|
||||
bool ay_bdir_, ay_bc1_;
|
||||
Cycles cycles_since_ay_update_;
|
||||
};
|
||||
VIA via_;
|
||||
std::shared_ptr<Keyboard> keyboard_;
|
||||
|
||||
// the Microdisc, if in use
|
||||
class Microdisc microdisc_;
|
||||
bool microdisc_is_enabled_;
|
||||
uint16_t ram_top_;
|
||||
uint8_t *paged_rom_;
|
||||
|
||||
inline void set_interrupt_line() {
|
||||
m6502_.set_irq_line(
|
||||
via_.get_interrupt_line() ||
|
||||
(microdisc_is_enabled_ && microdisc_.get_interrupt_request_line()));
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
using namespace Oric;
|
||||
|
||||
Machine::Machine() :
|
||||
m6502_(*this),
|
||||
use_fast_tape_hack_(false),
|
||||
typer_delay_(2500000),
|
||||
keyboard_read_count_(0),
|
||||
keyboard_(new Keyboard),
|
||||
ram_top_(0xbfff),
|
||||
paged_rom_(rom_),
|
||||
microdisc_is_enabled_(false) {
|
||||
set_clock_rate(1000000);
|
||||
via_.set_interrupt_delegate(this);
|
||||
via_.keyboard = keyboard_;
|
||||
clear_all_keys();
|
||||
via_.tape->set_delegate(this);
|
||||
Memory::Fuzz(ram_, sizeof(ram_));
|
||||
Machine *Machine::Oric() {
|
||||
return new ConcreteMachine;
|
||||
}
|
||||
|
||||
void Machine::configure_as_target(const StaticAnalyser::Target &target) {
|
||||
if(target.tapes.size()) {
|
||||
via_.tape->set_tape(target.tapes.front());
|
||||
}
|
||||
|
||||
if(target.loadingCommand.length()) {
|
||||
set_typer_for_string(target.loadingCommand.c_str());
|
||||
}
|
||||
|
||||
if(target.oric.has_microdisc) {
|
||||
microdisc_is_enabled_ = true;
|
||||
microdisc_did_change_paging_flags(µdisc_);
|
||||
microdisc_.set_delegate(this);
|
||||
}
|
||||
|
||||
int drive_index = 0;
|
||||
for(auto disk : target.disks) {
|
||||
if(drive_index < 4) microdisc_.set_disk(disk, drive_index);
|
||||
drive_index++;
|
||||
}
|
||||
|
||||
if(target.oric.use_atmos_rom) {
|
||||
memcpy(rom_, basic11_rom_.data(), std::min(basic11_rom_.size(), sizeof(rom_)));
|
||||
|
||||
is_using_basic11_ = true;
|
||||
tape_get_byte_address_ = 0xe6c9;
|
||||
scan_keyboard_address_ = 0xf495;
|
||||
tape_speed_address_ = 0x024d;
|
||||
} else {
|
||||
memcpy(rom_, basic10_rom_.data(), std::min(basic10_rom_.size(), sizeof(rom_)));
|
||||
|
||||
is_using_basic11_ = false;
|
||||
tape_get_byte_address_ = 0xe630;
|
||||
scan_keyboard_address_ = 0xf43c;
|
||||
tape_speed_address_ = 0x67;
|
||||
}
|
||||
}
|
||||
|
||||
void Machine::set_typer_for_string(const char *string) {
|
||||
std::unique_ptr<CharacterMapper> mapper(new CharacterMapper);
|
||||
Utility::TypeRecipient::set_typer_for_string(string, std::move(mapper));
|
||||
}
|
||||
|
||||
void Machine::set_rom(ROM rom, const std::vector<uint8_t> &data) {
|
||||
switch(rom) {
|
||||
case BASIC11: basic11_rom_ = std::move(data); break;
|
||||
case BASIC10: basic10_rom_ = std::move(data); break;
|
||||
case Microdisc: microdisc_rom_ = std::move(data); break;
|
||||
case Colour:
|
||||
colour_rom_ = std::move(data);
|
||||
if(video_output_) video_output_->set_colour_rom(colour_rom_);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Cycles Machine::perform_bus_operation(CPU::MOS6502::BusOperation operation, uint16_t address, uint8_t *value) {
|
||||
if(address > ram_top_) {
|
||||
if(isReadOperation(operation)) *value = paged_rom_[address - ram_top_ - 1];
|
||||
|
||||
// 024D = 0 => fast; otherwise slow
|
||||
// E6C9 = read byte: return byte in A
|
||||
if(address == tape_get_byte_address_ && paged_rom_ == rom_ && use_fast_tape_hack_ && operation == CPU::MOS6502::BusOperation::ReadOpcode && via_.tape->has_tape() && !via_.tape->get_tape()->is_at_end()) {
|
||||
uint8_t next_byte = via_.tape->get_next_byte(!ram_[tape_speed_address_]);
|
||||
m6502_.set_value_of_register(CPU::MOS6502::A, next_byte);
|
||||
m6502_.set_value_of_register(CPU::MOS6502::Flags, next_byte ? 0 : CPU::MOS6502::Flag::Zero);
|
||||
*value = 0x60; // i.e. RTS
|
||||
}
|
||||
} else {
|
||||
if((address & 0xff00) == 0x0300) {
|
||||
if(microdisc_is_enabled_ && address >= 0x0310) {
|
||||
switch(address) {
|
||||
case 0x0310: case 0x0311: case 0x0312: case 0x0313:
|
||||
if(isReadOperation(operation)) *value = microdisc_.get_register(address);
|
||||
else microdisc_.set_register(address, *value);
|
||||
break;
|
||||
case 0x314: case 0x315: case 0x316: case 0x317:
|
||||
if(isReadOperation(operation)) *value = microdisc_.get_interrupt_request_register();
|
||||
else microdisc_.set_control_register(*value);
|
||||
break;
|
||||
case 0x318: case 0x319: case 0x31a: case 0x31b:
|
||||
if(isReadOperation(operation)) *value = microdisc_.get_data_request_register();
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if(isReadOperation(operation)) *value = via_.get_register(address);
|
||||
else via_.set_register(address, *value);
|
||||
}
|
||||
} else {
|
||||
if(isReadOperation(operation))
|
||||
*value = ram_[address];
|
||||
else {
|
||||
if(address >= 0x9800 && address <= 0xc000) { update_video(); typer_delay_ = 0; }
|
||||
ram_[address] = *value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(typer_ && address == scan_keyboard_address_ && operation == CPU::MOS6502::BusOperation::ReadOpcode) {
|
||||
// the Oric 1 misses any key pressed on the very first entry into the read keyboard routine, so don't
|
||||
// do anything until at least the second, regardless of machine
|
||||
if(!keyboard_read_count_) keyboard_read_count_++;
|
||||
else if(!typer_->type_next_character()) {
|
||||
clear_all_keys();
|
||||
typer_.reset();
|
||||
}
|
||||
}
|
||||
|
||||
via_.run_for(Cycles(1));
|
||||
if(microdisc_is_enabled_) microdisc_.run_for(Cycles(8));
|
||||
cycles_since_video_update_++;
|
||||
return Cycles(1);
|
||||
}
|
||||
|
||||
void Machine::flush() {
|
||||
update_video();
|
||||
via_.flush();
|
||||
}
|
||||
|
||||
void Machine::update_video() {
|
||||
video_output_->run_for(cycles_since_video_update_.flush());
|
||||
}
|
||||
|
||||
void Machine::setup_output(float aspect_ratio) {
|
||||
via_.ay8910.reset(new GI::AY38910::AY38910());
|
||||
via_.ay8910->set_clock_rate(1000000);
|
||||
video_output_.reset(new VideoOutput(ram_));
|
||||
if(!colour_rom_.empty()) video_output_->set_colour_rom(colour_rom_);
|
||||
}
|
||||
|
||||
void Machine::close_output() {
|
||||
video_output_.reset();
|
||||
via_.ay8910.reset();
|
||||
}
|
||||
|
||||
void Machine::mos6522_did_change_interrupt_status(void *mos6522) {
|
||||
set_interrupt_line();
|
||||
}
|
||||
|
||||
void Machine::set_key_state(uint16_t key, bool isPressed) {
|
||||
if(key == KeyNMI) {
|
||||
m6502_.set_nmi_line(isPressed);
|
||||
} else {
|
||||
if(isPressed)
|
||||
keyboard_->rows[key >> 8] |= (key & 0xff);
|
||||
else
|
||||
keyboard_->rows[key >> 8] &= ~(key & 0xff);
|
||||
}
|
||||
}
|
||||
|
||||
void Machine::clear_all_keys() {
|
||||
memset(keyboard_->rows, 0, sizeof(keyboard_->rows));
|
||||
}
|
||||
|
||||
void Machine::set_use_fast_tape_hack(bool activate) {
|
||||
use_fast_tape_hack_ = activate;
|
||||
}
|
||||
|
||||
void Machine::set_output_device(Outputs::CRT::OutputDevice output_device) {
|
||||
video_output_->set_output_device(output_device);
|
||||
}
|
||||
|
||||
void Machine::tape_did_change_input(Storage::Tape::BinaryTapePlayer *tape_player) {
|
||||
// set CB1
|
||||
via_.set_control_line_input(VIA::Port::B, VIA::Line::One, !tape_player->get_input());
|
||||
}
|
||||
|
||||
std::shared_ptr<Outputs::CRT::CRT> Machine::get_crt() {
|
||||
return video_output_->get_crt();
|
||||
}
|
||||
|
||||
std::shared_ptr<Outputs::Speaker> Machine::get_speaker() {
|
||||
return via_.ay8910;
|
||||
}
|
||||
|
||||
void Machine::run_for(const Cycles cycles) {
|
||||
m6502_.run_for(cycles);
|
||||
}
|
||||
|
||||
#pragma mark - The 6522
|
||||
|
||||
Machine::VIA::VIA() :
|
||||
MOS::MOS6522<Machine::VIA>(),
|
||||
tape(new TapePlayer) {}
|
||||
|
||||
void Machine::VIA::set_control_line_output(Port port, Line line, bool value) {
|
||||
if(line) {
|
||||
if(port) ay_bdir_ = value; else ay_bc1_ = value;
|
||||
update_ay();
|
||||
}
|
||||
}
|
||||
|
||||
void Machine::VIA::set_port_output(Port port, uint8_t value, uint8_t direction_mask) {
|
||||
if(port) {
|
||||
keyboard->row = value;
|
||||
tape->set_motor_control(value & 0x40);
|
||||
} else {
|
||||
ay8910->set_data_input(value);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t Machine::VIA::get_port_input(Port port) {
|
||||
if(port) {
|
||||
uint8_t column = ay8910->get_port_output(false) ^ 0xff;
|
||||
return (keyboard->rows[keyboard->row & 7] & column) ? 0x08 : 0x00;
|
||||
} else {
|
||||
return ay8910->get_data_output();
|
||||
}
|
||||
}
|
||||
|
||||
void Machine::VIA::flush() {
|
||||
ay8910->run_for(cycles_since_ay_update_.flush());
|
||||
ay8910->flush();
|
||||
}
|
||||
|
||||
void Machine::VIA::run_for(const Cycles cycles) {
|
||||
cycles_since_ay_update_ += cycles;
|
||||
MOS::MOS6522<VIA>::run_for(cycles);
|
||||
tape->run_for(cycles);
|
||||
}
|
||||
|
||||
void Machine::VIA::update_ay() {
|
||||
ay8910->run_for(cycles_since_ay_update_.flush());
|
||||
ay8910->set_control_lines( (GI::AY38910::ControlLines)((ay_bdir_ ? GI::AY38910::BDIR : 0) | (ay_bc1_ ? GI::AY38910::BC1 : 0) | GI::AY38910::BC2));
|
||||
}
|
||||
|
||||
#pragma mark - TapePlayer
|
||||
|
||||
Machine::TapePlayer::TapePlayer() :
|
||||
Storage::Tape::BinaryTapePlayer(1000000) {}
|
||||
|
||||
uint8_t Machine::TapePlayer::get_next_byte(bool fast) {
|
||||
return (uint8_t)parser_.get_next_byte(get_tape(), fast);
|
||||
}
|
||||
|
||||
#pragma mark - Microdisc
|
||||
|
||||
void Machine::microdisc_did_change_paging_flags(class Microdisc *microdisc) {
|
||||
int flags = microdisc->get_paging_flags();
|
||||
if(!(flags&Microdisc::PagingFlags::BASICDisable)) {
|
||||
ram_top_ = 0xbfff;
|
||||
paged_rom_ = rom_;
|
||||
} else {
|
||||
if(flags&Microdisc::PagingFlags::MicrodscDisable) {
|
||||
ram_top_ = 0xffff;
|
||||
} else {
|
||||
ram_top_ = 0xdfff;
|
||||
paged_rom_ = microdisc_rom_.data();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Machine::wd1770_did_change_output(WD::WD1770 *wd1770) {
|
||||
set_interrupt_line();
|
||||
}
|
||||
|
||||
void Machine::set_interrupt_line() {
|
||||
m6502_.set_irq_line(
|
||||
via_.get_interrupt_line() ||
|
||||
(microdisc_is_enabled_ && microdisc_.get_interrupt_request_line()));
|
||||
}
|
||||
Machine::~Machine() {}
|
||||
|
@ -11,24 +11,17 @@
|
||||
|
||||
#include "../ConfigurationTarget.hpp"
|
||||
#include "../CRTMachine.hpp"
|
||||
#include "../Typer.hpp"
|
||||
|
||||
#include "../../Processors/6502/6502.hpp"
|
||||
#include "../../Components/6522/6522.hpp"
|
||||
#include "../../Components/AY38910/AY38910.hpp"
|
||||
#include "../../Storage/Tape/Parsers/Oric.hpp"
|
||||
|
||||
#include "Video.hpp"
|
||||
#include "Microdisc.hpp"
|
||||
|
||||
#include "../../Storage/Tape/Tape.hpp"
|
||||
#include "../KeyboardMachine.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
namespace Oric {
|
||||
|
||||
enum ROM {
|
||||
BASIC10, BASIC11, Microdisc, Colour
|
||||
};
|
||||
|
||||
enum Key: uint16_t {
|
||||
Key3 = 0x0000 | 0x80, KeyX = 0x0000 | 0x40, Key1 = 0x0000 | 0x20,
|
||||
KeyV = 0x0000 | 0x08, Key5 = 0x0000 | 0x04, KeyN = 0x0000 | 0x02, Key7 = 0x0000 | 0x01,
|
||||
@ -50,124 +43,27 @@ enum Key: uint16_t {
|
||||
KeyNMI = 0xfffd,
|
||||
};
|
||||
|
||||
enum ROM {
|
||||
BASIC10, BASIC11, Microdisc, Colour
|
||||
};
|
||||
|
||||
/*!
|
||||
Models an Oric 1/Atmos with or without a Microdisc.
|
||||
*/
|
||||
class Machine:
|
||||
public CPU::MOS6502::BusHandler,
|
||||
public CRTMachine::Machine,
|
||||
public ConfigurationTarget::Machine,
|
||||
public MOS::MOS6522IRQDelegate::Delegate,
|
||||
public Utility::TypeRecipient,
|
||||
public Storage::Tape::BinaryTapePlayer::Delegate,
|
||||
public Microdisc::Delegate {
|
||||
|
||||
public KeyboardMachine::Machine {
|
||||
public:
|
||||
Machine();
|
||||
virtual ~Machine();
|
||||
|
||||
void set_rom(ROM rom, const std::vector<uint8_t> &data);
|
||||
void set_key_state(uint16_t key, bool isPressed);
|
||||
void clear_all_keys();
|
||||
/// Creates an returns an Oric on the heap.
|
||||
static Machine *Oric();
|
||||
|
||||
void set_use_fast_tape_hack(bool activate);
|
||||
void set_output_device(Outputs::CRT::OutputDevice output_device);
|
||||
/// Sets the contents of @c rom to @c data. Assumed to be a setup step; has no effect once a machine is running.
|
||||
virtual void set_rom(ROM rom, const std::vector<uint8_t> &data) = 0;
|
||||
|
||||
// to satisfy ConfigurationTarget::Machine
|
||||
void configure_as_target(const StaticAnalyser::Target &target);
|
||||
/// Enables or disables turbo-speed tape loading.
|
||||
virtual void set_use_fast_tape_hack(bool activate) = 0;
|
||||
|
||||
// to satisfy CPU::MOS6502::Processor
|
||||
Cycles perform_bus_operation(CPU::MOS6502::BusOperation operation, uint16_t address, uint8_t *value);
|
||||
void 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();
|
||||
virtual std::shared_ptr<Outputs::Speaker> get_speaker();
|
||||
virtual void run_for(const Cycles cycles);
|
||||
|
||||
// to satisfy MOS::MOS6522IRQDelegate::Delegate
|
||||
void mos6522_did_change_interrupt_status(void *mos6522);
|
||||
|
||||
// to satisfy Storage::Tape::BinaryTapePlayer::Delegate
|
||||
void tape_did_change_input(Storage::Tape::BinaryTapePlayer *tape_player);
|
||||
|
||||
// for Utility::TypeRecipient::Delegate
|
||||
void set_typer_for_string(const char *string);
|
||||
|
||||
// for Microdisc::Delegate
|
||||
void microdisc_did_change_paging_flags(class Microdisc *microdisc);
|
||||
void wd1770_did_change_output(WD::WD1770 *wd1770);
|
||||
|
||||
private:
|
||||
CPU::MOS6502::Processor<Machine> m6502_;
|
||||
|
||||
// RAM and ROM
|
||||
std::vector<uint8_t> basic11_rom_, basic10_rom_, microdisc_rom_, colour_rom_;
|
||||
uint8_t ram_[65536], rom_[16384];
|
||||
Cycles cycles_since_video_update_;
|
||||
inline void update_video();
|
||||
|
||||
// ROM bookkeeping
|
||||
bool is_using_basic11_;
|
||||
uint16_t tape_get_byte_address_, scan_keyboard_address_, tape_speed_address_;
|
||||
int keyboard_read_count_;
|
||||
|
||||
// Outputs
|
||||
std::unique_ptr<VideoOutput> video_output_;
|
||||
|
||||
// Keyboard
|
||||
class Keyboard {
|
||||
public:
|
||||
uint8_t row;
|
||||
uint8_t rows[8];
|
||||
};
|
||||
int typer_delay_;
|
||||
|
||||
// The tape
|
||||
class TapePlayer: public Storage::Tape::BinaryTapePlayer {
|
||||
public:
|
||||
TapePlayer();
|
||||
uint8_t get_next_byte(bool fast);
|
||||
|
||||
private:
|
||||
Storage::Tape::Oric::Parser parser_;
|
||||
};
|
||||
bool use_fast_tape_hack_;
|
||||
|
||||
// VIA (which owns the tape and the AY)
|
||||
class VIA: public MOS::MOS6522<VIA>, public MOS::MOS6522IRQDelegate {
|
||||
public:
|
||||
VIA();
|
||||
using MOS6522IRQDelegate::set_interrupt_status;
|
||||
|
||||
void set_control_line_output(Port port, Line line, bool value);
|
||||
void set_port_output(Port port, uint8_t value, uint8_t direction_mask);
|
||||
uint8_t get_port_input(Port port);
|
||||
inline void run_for(const Cycles cycles);
|
||||
|
||||
std::shared_ptr<GI::AY38910::AY38910> ay8910;
|
||||
std::unique_ptr<TapePlayer> tape;
|
||||
std::shared_ptr<Keyboard> keyboard;
|
||||
|
||||
void flush();
|
||||
|
||||
private:
|
||||
void update_ay();
|
||||
bool ay_bdir_, ay_bc1_;
|
||||
Cycles cycles_since_ay_update_;
|
||||
};
|
||||
VIA via_;
|
||||
std::shared_ptr<Keyboard> keyboard_;
|
||||
|
||||
// the Microdisc, if in use
|
||||
class Microdisc microdisc_;
|
||||
bool microdisc_is_enabled_;
|
||||
uint16_t ram_top_;
|
||||
uint8_t *paged_rom_;
|
||||
|
||||
inline void set_interrupt_line();
|
||||
/// Sets the type of display the Oric is connected to.
|
||||
virtual void set_output_device(Outputs::CRT::OutputDevice output_device) = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -16,7 +16,14 @@
|
||||
#import "NSBundle+DataResource.h"
|
||||
|
||||
@implementation CSOric {
|
||||
Oric::Machine _oric;
|
||||
std::unique_ptr<Oric::Machine> _oric;
|
||||
}
|
||||
|
||||
- (CRTMachine::Machine * const)machine {
|
||||
if(!_oric) {
|
||||
_oric.reset(Oric::Machine::Oric());
|
||||
}
|
||||
return _oric.get();
|
||||
}
|
||||
|
||||
- (instancetype)init {
|
||||
@ -27,10 +34,10 @@
|
||||
NSData *colour = [self rom:@"colour"];
|
||||
NSData *microdisc = [self rom:@"microdisc"];
|
||||
|
||||
if(basic10) _oric.set_rom(Oric::BASIC10, basic10.stdVector8);
|
||||
if(basic11) _oric.set_rom(Oric::BASIC11, basic11.stdVector8);
|
||||
if(colour) _oric.set_rom(Oric::Colour, colour.stdVector8);
|
||||
if(microdisc) _oric.set_rom(Oric::Microdisc, microdisc.stdVector8);
|
||||
if(basic10) _oric->set_rom(Oric::BASIC10, basic10.stdVector8);
|
||||
if(basic11) _oric->set_rom(Oric::BASIC11, basic11.stdVector8);
|
||||
if(colour) _oric->set_rom(Oric::Colour, colour.stdVector8);
|
||||
if(microdisc) _oric->set_rom(Oric::Microdisc, microdisc.stdVector8);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
@ -39,89 +46,85 @@
|
||||
return [[NSBundle mainBundle] dataForResource:name withExtension:@"rom" subdirectory:@"ROMImages/Oric"];
|
||||
}
|
||||
|
||||
- (CRTMachine::Machine * const)machine {
|
||||
return &_oric;
|
||||
}
|
||||
|
||||
#pragma mark - CSKeyboardMachine
|
||||
|
||||
- (void)setKey:(uint16_t)key isPressed:(BOOL)isPressed {
|
||||
@synchronized(self) {
|
||||
switch(key) {
|
||||
case VK_ANSI_0: _oric.set_key_state(Oric::Key::Key0, isPressed); break;
|
||||
case VK_ANSI_1: _oric.set_key_state(Oric::Key::Key1, isPressed); break;
|
||||
case VK_ANSI_2: _oric.set_key_state(Oric::Key::Key2, isPressed); break;
|
||||
case VK_ANSI_3: _oric.set_key_state(Oric::Key::Key3, isPressed); break;
|
||||
case VK_ANSI_4: _oric.set_key_state(Oric::Key::Key4, isPressed); break;
|
||||
case VK_ANSI_5: _oric.set_key_state(Oric::Key::Key5, isPressed); break;
|
||||
case VK_ANSI_6: _oric.set_key_state(Oric::Key::Key6, isPressed); break;
|
||||
case VK_ANSI_7: _oric.set_key_state(Oric::Key::Key7, isPressed); break;
|
||||
case VK_ANSI_8: _oric.set_key_state(Oric::Key::Key8, isPressed); break;
|
||||
case VK_ANSI_9: _oric.set_key_state(Oric::Key::Key9, isPressed); break;
|
||||
case VK_ANSI_0: _oric->set_key_state(Oric::Key::Key0, isPressed); break;
|
||||
case VK_ANSI_1: _oric->set_key_state(Oric::Key::Key1, isPressed); break;
|
||||
case VK_ANSI_2: _oric->set_key_state(Oric::Key::Key2, isPressed); break;
|
||||
case VK_ANSI_3: _oric->set_key_state(Oric::Key::Key3, isPressed); break;
|
||||
case VK_ANSI_4: _oric->set_key_state(Oric::Key::Key4, isPressed); break;
|
||||
case VK_ANSI_5: _oric->set_key_state(Oric::Key::Key5, isPressed); break;
|
||||
case VK_ANSI_6: _oric->set_key_state(Oric::Key::Key6, isPressed); break;
|
||||
case VK_ANSI_7: _oric->set_key_state(Oric::Key::Key7, isPressed); break;
|
||||
case VK_ANSI_8: _oric->set_key_state(Oric::Key::Key8, isPressed); break;
|
||||
case VK_ANSI_9: _oric->set_key_state(Oric::Key::Key9, isPressed); break;
|
||||
|
||||
case VK_ANSI_Q: _oric.set_key_state(Oric::Key::KeyQ, isPressed); break;
|
||||
case VK_ANSI_W: _oric.set_key_state(Oric::Key::KeyW, isPressed); break;
|
||||
case VK_ANSI_E: _oric.set_key_state(Oric::Key::KeyE, isPressed); break;
|
||||
case VK_ANSI_R: _oric.set_key_state(Oric::Key::KeyR, isPressed); break;
|
||||
case VK_ANSI_T: _oric.set_key_state(Oric::Key::KeyT, isPressed); break;
|
||||
case VK_ANSI_Y: _oric.set_key_state(Oric::Key::KeyY, isPressed); break;
|
||||
case VK_ANSI_U: _oric.set_key_state(Oric::Key::KeyU, isPressed); break;
|
||||
case VK_ANSI_I: _oric.set_key_state(Oric::Key::KeyI, isPressed); break;
|
||||
case VK_ANSI_O: _oric.set_key_state(Oric::Key::KeyO, isPressed); break;
|
||||
case VK_ANSI_P: _oric.set_key_state(Oric::Key::KeyP, isPressed); break;
|
||||
case VK_ANSI_A: _oric.set_key_state(Oric::Key::KeyA, isPressed); break;
|
||||
case VK_ANSI_S: _oric.set_key_state(Oric::Key::KeyS, isPressed); break;
|
||||
case VK_ANSI_D: _oric.set_key_state(Oric::Key::KeyD, isPressed); break;
|
||||
case VK_ANSI_F: _oric.set_key_state(Oric::Key::KeyF, isPressed); break;
|
||||
case VK_ANSI_G: _oric.set_key_state(Oric::Key::KeyG, isPressed); break;
|
||||
case VK_ANSI_H: _oric.set_key_state(Oric::Key::KeyH, isPressed); break;
|
||||
case VK_ANSI_J: _oric.set_key_state(Oric::Key::KeyJ, isPressed); break;
|
||||
case VK_ANSI_K: _oric.set_key_state(Oric::Key::KeyK, isPressed); break;
|
||||
case VK_ANSI_L: _oric.set_key_state(Oric::Key::KeyL, isPressed); break;
|
||||
case VK_ANSI_Z: _oric.set_key_state(Oric::Key::KeyZ, isPressed); break;
|
||||
case VK_ANSI_X: _oric.set_key_state(Oric::Key::KeyX, isPressed); break;
|
||||
case VK_ANSI_C: _oric.set_key_state(Oric::Key::KeyC, isPressed); break;
|
||||
case VK_ANSI_V: _oric.set_key_state(Oric::Key::KeyV, isPressed); break;
|
||||
case VK_ANSI_B: _oric.set_key_state(Oric::Key::KeyB, isPressed); break;
|
||||
case VK_ANSI_N: _oric.set_key_state(Oric::Key::KeyN, isPressed); break;
|
||||
case VK_ANSI_M: _oric.set_key_state(Oric::Key::KeyM, isPressed); break;
|
||||
case VK_ANSI_Q: _oric->set_key_state(Oric::Key::KeyQ, isPressed); break;
|
||||
case VK_ANSI_W: _oric->set_key_state(Oric::Key::KeyW, isPressed); break;
|
||||
case VK_ANSI_E: _oric->set_key_state(Oric::Key::KeyE, isPressed); break;
|
||||
case VK_ANSI_R: _oric->set_key_state(Oric::Key::KeyR, isPressed); break;
|
||||
case VK_ANSI_T: _oric->set_key_state(Oric::Key::KeyT, isPressed); break;
|
||||
case VK_ANSI_Y: _oric->set_key_state(Oric::Key::KeyY, isPressed); break;
|
||||
case VK_ANSI_U: _oric->set_key_state(Oric::Key::KeyU, isPressed); break;
|
||||
case VK_ANSI_I: _oric->set_key_state(Oric::Key::KeyI, isPressed); break;
|
||||
case VK_ANSI_O: _oric->set_key_state(Oric::Key::KeyO, isPressed); break;
|
||||
case VK_ANSI_P: _oric->set_key_state(Oric::Key::KeyP, isPressed); break;
|
||||
case VK_ANSI_A: _oric->set_key_state(Oric::Key::KeyA, isPressed); break;
|
||||
case VK_ANSI_S: _oric->set_key_state(Oric::Key::KeyS, isPressed); break;
|
||||
case VK_ANSI_D: _oric->set_key_state(Oric::Key::KeyD, isPressed); break;
|
||||
case VK_ANSI_F: _oric->set_key_state(Oric::Key::KeyF, isPressed); break;
|
||||
case VK_ANSI_G: _oric->set_key_state(Oric::Key::KeyG, isPressed); break;
|
||||
case VK_ANSI_H: _oric->set_key_state(Oric::Key::KeyH, isPressed); break;
|
||||
case VK_ANSI_J: _oric->set_key_state(Oric::Key::KeyJ, isPressed); break;
|
||||
case VK_ANSI_K: _oric->set_key_state(Oric::Key::KeyK, isPressed); break;
|
||||
case VK_ANSI_L: _oric->set_key_state(Oric::Key::KeyL, isPressed); break;
|
||||
case VK_ANSI_Z: _oric->set_key_state(Oric::Key::KeyZ, isPressed); break;
|
||||
case VK_ANSI_X: _oric->set_key_state(Oric::Key::KeyX, isPressed); break;
|
||||
case VK_ANSI_C: _oric->set_key_state(Oric::Key::KeyC, isPressed); break;
|
||||
case VK_ANSI_V: _oric->set_key_state(Oric::Key::KeyV, isPressed); break;
|
||||
case VK_ANSI_B: _oric->set_key_state(Oric::Key::KeyB, isPressed); break;
|
||||
case VK_ANSI_N: _oric->set_key_state(Oric::Key::KeyN, isPressed); break;
|
||||
case VK_ANSI_M: _oric->set_key_state(Oric::Key::KeyM, isPressed); break;
|
||||
|
||||
case VK_Space: _oric.set_key_state(Oric::Key::KeySpace, isPressed); break;
|
||||
case VK_Return: _oric.set_key_state(Oric::Key::KeyReturn, isPressed); break;
|
||||
case VK_ANSI_Minus: _oric.set_key_state(Oric::Key::KeyMinus, isPressed); break;
|
||||
case VK_ANSI_Equal: _oric.set_key_state(Oric::Key::KeyEquals, isPressed); break;
|
||||
case VK_Space: _oric->set_key_state(Oric::Key::KeySpace, isPressed); break;
|
||||
case VK_Return: _oric->set_key_state(Oric::Key::KeyReturn, isPressed); break;
|
||||
case VK_ANSI_Minus: _oric->set_key_state(Oric::Key::KeyMinus, isPressed); break;
|
||||
case VK_ANSI_Equal: _oric->set_key_state(Oric::Key::KeyEquals, isPressed); break;
|
||||
case VK_ANSI_Backslash:
|
||||
_oric.set_key_state(Oric::Key::KeyBackSlash, isPressed); break;
|
||||
case VK_ANSI_Slash: _oric.set_key_state(Oric::Key::KeyForwardSlash, isPressed); break;
|
||||
_oric->set_key_state(Oric::Key::KeyBackSlash, isPressed); break;
|
||||
case VK_ANSI_Slash: _oric->set_key_state(Oric::Key::KeyForwardSlash, isPressed); break;
|
||||
|
||||
case VK_ANSI_LeftBracket:
|
||||
_oric.set_key_state(Oric::Key::KeyOpenSquare, isPressed); break;
|
||||
_oric->set_key_state(Oric::Key::KeyOpenSquare, isPressed); break;
|
||||
case VK_ANSI_RightBracket:
|
||||
_oric.set_key_state(Oric::Key::KeyCloseSquare, isPressed); break;
|
||||
case VK_ANSI_Quote: _oric.set_key_state(Oric::Key::KeyQuote, isPressed); break;
|
||||
_oric->set_key_state(Oric::Key::KeyCloseSquare, isPressed); break;
|
||||
case VK_ANSI_Quote: _oric->set_key_state(Oric::Key::KeyQuote, isPressed); break;
|
||||
|
||||
case VK_RightArrow: _oric.set_key_state(Oric::Key::KeyRight, isPressed); break;
|
||||
case VK_LeftArrow: _oric.set_key_state(Oric::Key::KeyLeft, isPressed); break;
|
||||
case VK_DownArrow: _oric.set_key_state(Oric::Key::KeyDown, isPressed); break;
|
||||
case VK_UpArrow: _oric.set_key_state(Oric::Key::KeyUp, isPressed); break;
|
||||
case VK_RightArrow: _oric->set_key_state(Oric::Key::KeyRight, isPressed); break;
|
||||
case VK_LeftArrow: _oric->set_key_state(Oric::Key::KeyLeft, isPressed); break;
|
||||
case VK_DownArrow: _oric->set_key_state(Oric::Key::KeyDown, isPressed); break;
|
||||
case VK_UpArrow: _oric->set_key_state(Oric::Key::KeyUp, isPressed); break;
|
||||
|
||||
case VK_Delete: _oric.set_key_state(Oric::Key::KeyDelete, isPressed); break;
|
||||
case VK_Escape: _oric.set_key_state(Oric::Key::KeyEscape, isPressed); break;
|
||||
case VK_Delete: _oric->set_key_state(Oric::Key::KeyDelete, isPressed); break;
|
||||
case VK_Escape: _oric->set_key_state(Oric::Key::KeyEscape, isPressed); break;
|
||||
|
||||
case VK_ANSI_Comma: _oric.set_key_state(Oric::Key::KeyComma, isPressed); break;
|
||||
case VK_ANSI_Period: _oric.set_key_state(Oric::Key::KeyFullStop, isPressed); break;
|
||||
case VK_ANSI_Comma: _oric->set_key_state(Oric::Key::KeyComma, isPressed); break;
|
||||
case VK_ANSI_Period: _oric->set_key_state(Oric::Key::KeyFullStop, isPressed); break;
|
||||
|
||||
case VK_ANSI_Semicolon: _oric.set_key_state(Oric::Key::KeySemiColon, isPressed); break;
|
||||
case VK_ANSI_Semicolon: _oric->set_key_state(Oric::Key::KeySemiColon, isPressed); break;
|
||||
|
||||
case VK_Shift:
|
||||
_oric.set_key_state(Oric::Key::KeyLeftShift, isPressed);
|
||||
_oric.set_key_state(Oric::Key::KeyRightShift, isPressed);
|
||||
_oric->set_key_state(Oric::Key::KeyLeftShift, isPressed);
|
||||
_oric->set_key_state(Oric::Key::KeyRightShift, isPressed);
|
||||
break;
|
||||
case VK_RightShift: _oric.set_key_state(Oric::Key::KeyRightShift, isPressed); break;
|
||||
case VK_Control: _oric.set_key_state(Oric::Key::KeyControl, isPressed); break;
|
||||
case VK_RightShift: _oric->set_key_state(Oric::Key::KeyRightShift, isPressed); break;
|
||||
case VK_Control: _oric->set_key_state(Oric::Key::KeyControl, isPressed); break;
|
||||
|
||||
case VK_ANSI_Grave:
|
||||
case VK_F12: _oric.set_key_state(Oric::Key::KeyNMI, isPressed); break;
|
||||
case VK_F12: _oric->set_key_state(Oric::Key::KeyNMI, isPressed); break;
|
||||
|
||||
default:
|
||||
printf("%02x\n", key);
|
||||
@ -131,7 +134,9 @@
|
||||
}
|
||||
|
||||
- (void)clearAllKeys {
|
||||
_oric.clear_all_keys();
|
||||
@synchronized(self) {
|
||||
_oric->clear_all_keys();
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Options
|
||||
@ -139,14 +144,14 @@
|
||||
- (void)setUseFastLoadingHack:(BOOL)useFastLoadingHack {
|
||||
@synchronized(self) {
|
||||
_useFastLoadingHack = useFastLoadingHack;
|
||||
_oric.set_use_fast_tape_hack(useFastLoadingHack ? true : false);
|
||||
_oric->set_use_fast_tape_hack(useFastLoadingHack ? true : false);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setUseCompositeOutput:(BOOL)useCompositeOutput {
|
||||
@synchronized(self) {
|
||||
_useCompositeOutput = useCompositeOutput;
|
||||
_oric.set_output_device(useCompositeOutput ? Outputs::CRT::Television : Outputs::CRT::Monitor);
|
||||
_oric->set_output_device(useCompositeOutput ? Outputs::CRT::Television : Outputs::CRT::Monitor);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user