1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-11-25 16:31:42 +00:00
CLK/Machines/Oric/Oric.hpp

176 lines
5.4 KiB
C++

//
// Oric.hpp
// Clock Signal
//
// Created by Thomas Harte on 11/10/2016.
// Copyright © 2016 Thomas Harte. All rights reserved.
//
#ifndef Oric_hpp
#define Oric_hpp
#include "../../Processors/6502/CPU6502.hpp"
#include "../../Components/6522/6522.hpp"
#include "../../Components/AY38910/AY38910.hpp"
#include "../../Storage/Tape/Tape.hpp"
#include "../ConfigurationTarget.hpp"
#include "../CRTMachine.hpp"
#include "../Typer.hpp"
#include "Video.hpp"
#include <cstdint>
#include <vector>
#include <memory>
namespace Oric {
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,
KeyD = 0x0100 | 0x80, KeyQ = 0x0100 | 0x40, KeyEscape = 0x0100 | 0x20,
KeyF = 0x0100 | 0x08, KeyR = 0x0100 | 0x04, KeyT = 0x0100 | 0x02, KeyJ = 0x0100 | 0x01,
KeyC = 0x0200 | 0x80, Key2 = 0x0200 | 0x40, KeyZ = 0x0200 | 0x20, KeyControl = 0x0200 | 0x10,
Key4 = 0x0200 | 0x08, KeyB = 0x0200 | 0x04, Key6 = 0x0200 | 0x02, KeyM = 0x0200 | 0x01,
KeyQuote = 0x0300 | 0x80, KeyBackSlash = 0x0300 | 0x40,
KeyMinus = 0x0300 | 0x08, KeySemiColon = 0x0300 | 0x04, Key9 = 0x0300 | 0x02, KeyK = 0x0300 | 0x01,
KeyRight = 0x0400 | 0x80, KeyDown = 0x0400 | 0x40, KeyLeft = 0x0400 | 0x20, KeyLeftShift = 0x0400 | 0x10,
KeyUp = 0x0400 | 0x08, KeyFullStop = 0x0400 | 0x04, KeyComma = 0x0400 | 0x02, KeySpace = 0x0400 | 0x01,
KeyOpenSquare = 0x0500 | 0x80, KeyCloseSquare = 0x0500 | 0x40, KeyDelete = 0x0500 | 0x20, KeyFunction = 0x0500 | 0x10,
KeyP = 0x0500 | 0x08, KeyO = 0x0500 | 0x04, KeyI = 0x0500 | 0x02, KeyU = 0x0500 | 0x01,
KeyW = 0x0600 | 0x80, KeyS = 0x0600 | 0x40, KeyA = 0x0600 | 0x20,
KeyE = 0x0600 | 0x08, KeyG = 0x0600 | 0x04, KeyH = 0x0600 | 0x02, KeyY = 0x0600 | 0x01,
KeyEquals = 0x0700 | 0x80, KeyReturn = 0x0700 | 0x20, KeyRightShift = 0x0700 | 0x10,
KeyForwardSlash = 0x0700 | 0x08, Key0 = 0x0700 | 0x04, KeyL = 0x0700 | 0x02, Key8 = 0x0700 | 0x01,
KeyNMI = 0xffff,
};
class Machine:
public CPU6502::Processor<Machine>,
public CRTMachine::Machine,
public ConfigurationTarget::Machine,
public MOS::MOS6522IRQDelegate::Delegate,
public Storage::Tape::BinaryTapePlayer::Delegate {
public:
Machine();
void set_rom(std::vector<uint8_t> data);
void set_key_state(Key key, bool isPressed);
void clear_all_keys();
// to satisfy ConfigurationTarget::Machine
void configure_as_target(const StaticAnalyser::Target &target);
// to satisfy CPU6502::Processor
unsigned int perform_bus_operation(CPU6502::BusOperation operation, uint16_t address, uint8_t *value);
void synchronise();
// 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 _videoOutput->get_crt(); }
virtual std::shared_ptr<Outputs::Speaker> get_speaker() { return _via.ay8910; }
virtual void run_for_cycles(int number_of_cycles) { CPU6502::Processor<Machine>::run_for_cycles(number_of_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);
private:
// RAM and ROM
uint8_t _ram[65536], _rom[16384];
int _cycles_since_video_update;
inline void update_video();
// Outputs
std::unique_ptr<VideoOutput> _videoOutput;
// Keyboard
class Keyboard {
public:
uint8_t row;
uint8_t rows[8];
};
// VIA (which owns the tape and the AY)
class VIA: public MOS::MOS6522<VIA>, public MOS::MOS6522IRQDelegate {
public:
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
{
_port_a_output = value;
update_ay();
}
}
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 _port_a_input;
}
}
inline void run_for_half_cycles(unsigned int number_of_cycles)
{
_half_cycles_since_ay_update += number_of_cycles;
MOS::MOS6522<VIA>::run_for_half_cycles(number_of_cycles);
}
std::shared_ptr<GI::AY38910> ay8910;
std::shared_ptr<Storage::Tape::BinaryTapePlayer> tape;
std::shared_ptr<Keyboard> keyboard;
inline void synchronise() { update_ay(); }
private:
void update_ay()
{
ay8910->run_for_cycles(_half_cycles_since_ay_update >> 1);
_half_cycles_since_ay_update &= 1;
if(_ay_bdir)
{
if(_ay_bc1) ay8910->select_register(_port_a_output);
else ay8910->set_register_value(_port_a_output);
}
else
{
if(_ay_bc1) _port_a_input = ay8910->get_register_value();
}
}
uint8_t _port_a_output, _port_a_input;
bool _ay_bdir, _ay_bc1;
unsigned int _half_cycles_since_ay_update;
};
VIA _via;
std::shared_ptr<Keyboard> _keyboard;
};
}
#endif /* Oric_hpp */