mirror of
https://github.com/TomHarte/CLK.git
synced 2024-11-29 12:50:28 +00:00
With some time additions to the 6522, starts wiring in Macintosh audio.
The audio buffer is also the disk motor buffer, so this is preparatory to further disk work.
This commit is contained in:
parent
938928865d
commit
723137c0d4
@ -47,6 +47,12 @@ class PortHandler {
|
|||||||
|
|
||||||
/// Sets the current logical value of the interrupt line.
|
/// Sets the current logical value of the interrupt line.
|
||||||
void set_interrupt_status(bool status) {}
|
void set_interrupt_status(bool status) {}
|
||||||
|
|
||||||
|
/// Provides a measure of time elapsed between other calls.
|
||||||
|
void run_for(HalfCycles duration) {}
|
||||||
|
|
||||||
|
/// Receives passed-on flush() calls from the 6522.
|
||||||
|
void flush() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ -108,12 +114,17 @@ template <class T> class MOS6522: public MOS6522Storage {
|
|||||||
/// @returns @c true if the IRQ line is currently active; @c false otherwise.
|
/// @returns @c true if the IRQ line is currently active; @c false otherwise.
|
||||||
bool get_interrupt_line();
|
bool get_interrupt_line();
|
||||||
|
|
||||||
|
/// Updates the port handler to the current time and then requests that it flush.
|
||||||
|
void flush();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void do_phase1();
|
void do_phase1();
|
||||||
void do_phase2();
|
void do_phase2();
|
||||||
void shift_in();
|
void shift_in();
|
||||||
void shift_out();
|
void shift_out();
|
||||||
|
|
||||||
T &bus_handler_;
|
T &bus_handler_;
|
||||||
|
HalfCycles time_since_bus_handler_call_;
|
||||||
|
|
||||||
void access(int address);
|
void access(int address);
|
||||||
|
|
||||||
|
@ -37,6 +37,8 @@ template <typename T> void MOS6522<T>::set_register(int address, uint8_t value)
|
|||||||
case 0x0: // Write Port B.
|
case 0x0: // Write Port B.
|
||||||
// Store locally and communicate outwards.
|
// Store locally and communicate outwards.
|
||||||
registers_.output[1] = value;
|
registers_.output[1] = value;
|
||||||
|
|
||||||
|
bus_handler_.run_for(time_since_bus_handler_call_.flush());
|
||||||
bus_handler_.set_port_output(Port::B, value, registers_.data_direction[1]);
|
bus_handler_.set_port_output(Port::B, value, registers_.data_direction[1]);
|
||||||
|
|
||||||
registers_.interrupt_flags &= ~(InterruptFlag::CB1ActiveEdge | ((registers_.peripheral_control&0x20) ? 0 : InterruptFlag::CB2ActiveEdge));
|
registers_.interrupt_flags &= ~(InterruptFlag::CB1ActiveEdge | ((registers_.peripheral_control&0x20) ? 0 : InterruptFlag::CB2ActiveEdge));
|
||||||
@ -45,6 +47,8 @@ template <typename T> void MOS6522<T>::set_register(int address, uint8_t value)
|
|||||||
case 0xf:
|
case 0xf:
|
||||||
case 0x1: // Write Port A.
|
case 0x1: // Write Port A.
|
||||||
registers_.output[0] = value;
|
registers_.output[0] = value;
|
||||||
|
|
||||||
|
bus_handler_.run_for(time_since_bus_handler_call_.flush());
|
||||||
bus_handler_.set_port_output(Port::A, value, registers_.data_direction[0]);
|
bus_handler_.set_port_output(Port::A, value, registers_.data_direction[0]);
|
||||||
|
|
||||||
if(handshake_modes_[1] != HandshakeMode::None) {
|
if(handshake_modes_[1] != HandshakeMode::None) {
|
||||||
@ -193,7 +197,8 @@ template <typename T> uint8_t MOS6522<T>::get_register(int address) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename T> uint8_t MOS6522<T>::get_port_input(Port port, uint8_t output_mask, uint8_t output) {
|
template <typename T> uint8_t MOS6522<T>::get_port_input(Port port, uint8_t output_mask, uint8_t output) {
|
||||||
uint8_t input = bus_handler_.get_port_input(port);
|
bus_handler_.run_for(time_since_bus_handler_call_.flush());
|
||||||
|
const uint8_t input = bus_handler_.get_port_input(port);
|
||||||
return (input & ~output_mask) | (output & output_mask);
|
return (input & ~output_mask) | (output & output_mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -206,6 +211,8 @@ template <typename T> void MOS6522<T>::reevaluate_interrupts() {
|
|||||||
bool new_interrupt_status = get_interrupt_line();
|
bool new_interrupt_status = get_interrupt_line();
|
||||||
if(new_interrupt_status != last_posted_interrupt_status_) {
|
if(new_interrupt_status != last_posted_interrupt_status_) {
|
||||||
last_posted_interrupt_status_ = new_interrupt_status;
|
last_posted_interrupt_status_ = new_interrupt_status;
|
||||||
|
|
||||||
|
bus_handler_.run_for(time_since_bus_handler_call_.flush());
|
||||||
bus_handler_.set_interrupt_status(new_interrupt_status);
|
bus_handler_.set_interrupt_status(new_interrupt_status);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -251,6 +258,8 @@ template <typename T> void MOS6522<T>::set_control_line_input(Port port, Line li
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename T> void MOS6522<T>::do_phase2() {
|
template <typename T> void MOS6522<T>::do_phase2() {
|
||||||
|
++ time_since_bus_handler_call_;
|
||||||
|
|
||||||
registers_.last_timer[0] = registers_.timer[0];
|
registers_.last_timer[0] = registers_.timer[0];
|
||||||
registers_.last_timer[1] = registers_.timer[1];
|
registers_.last_timer[1] = registers_.timer[1];
|
||||||
|
|
||||||
@ -281,6 +290,8 @@ template <typename T> void MOS6522<T>::do_phase2() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename T> void MOS6522<T>::do_phase1() {
|
template <typename T> void MOS6522<T>::do_phase1() {
|
||||||
|
++ time_since_bus_handler_call_;
|
||||||
|
|
||||||
// IRQ is raised on the half cycle after overflow
|
// IRQ is raised on the half cycle after overflow
|
||||||
if((registers_.timer[1] == 0xffff) && !registers_.last_timer[1] && timer_is_running_[1]) {
|
if((registers_.timer[1] == 0xffff) && !registers_.last_timer[1] && timer_is_running_[1]) {
|
||||||
timer_is_running_[1] = false;
|
timer_is_running_[1] = false;
|
||||||
@ -339,6 +350,11 @@ template <typename T> void MOS6522<T>::run_for(const HalfCycles half_cycles) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T> void MOS6522<T>::flush() {
|
||||||
|
bus_handler_.run_for(time_since_bus_handler_call_.flush());
|
||||||
|
bus_handler_.flush();
|
||||||
|
}
|
||||||
|
|
||||||
/*! Runs for a specified number of cycles. */
|
/*! Runs for a specified number of cycles. */
|
||||||
template <typename T> void MOS6522<T>::run_for(const Cycles cycles) {
|
template <typename T> void MOS6522<T>::run_for(const Cycles cycles) {
|
||||||
int number_of_cycles = cycles.as_int();
|
int number_of_cycles = cycles.as_int();
|
||||||
@ -363,6 +379,7 @@ template <typename T> void MOS6522<T>::set_control_line_output(Port port, Line l
|
|||||||
// control line is actually in output mode.
|
// control line is actually in output mode.
|
||||||
control_outputs_[port].lines[line] = value;
|
control_outputs_[port].lines[line] = value;
|
||||||
if(registers_.peripheral_control & (0x08 << (port * 4))) {
|
if(registers_.peripheral_control & (0x08 << (port * 4))) {
|
||||||
|
bus_handler_.run_for(time_since_bus_handler_call_.flush());
|
||||||
bus_handler_.set_control_line_output(port, line, value);
|
bus_handler_.set_control_line_output(port, line, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -38,11 +38,14 @@ uint8_t IWM::read(int address) {
|
|||||||
// you must first turn off Q7 by reading or writing dBase+q7L. Then turn on Q6 by accessing dBase+q6H.
|
// you must first turn off Q7 by reading or writing dBase+q7L. Then turn on Q6 by accessing dBase+q6H.
|
||||||
// After that, the IWM will be able to pass data from the disk's RD/SENSE line through to you."
|
// After that, the IWM will be able to pass data from the disk's RD/SENSE line through to you."
|
||||||
//
|
//
|
||||||
// My thoughts: I'm unclear on how passing data from RD/SENSE is conflated with reading "any of the disk
|
// My understanding:
|
||||||
// registers", but the text reads as though the access happens internally but isn't passed on in the case
|
//
|
||||||
// of Q6 and Q7 being in the incorrect state.
|
// Q6 = 1, Q7 = 0 reads the status register. The meaning of the top 'SENSE' bit is then determined by
|
||||||
|
// the CA0,1,2 and SEL switches as described in Inside Macintosh, summarised above as RD/SENSE.
|
||||||
|
|
||||||
printf("Read %d: ", address&1);
|
if(address&1) {
|
||||||
|
return 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
switch(state_ & (Q6 | Q7 | ENABLE)) {
|
switch(state_ & (Q6 | Q7 | ENABLE)) {
|
||||||
default:
|
default:
|
||||||
@ -73,7 +76,7 @@ uint8_t IWM::read(int address) {
|
|||||||
printf("Reading status ([%d] including ", (state_&DRIVESEL) ? 2 : 1);
|
printf("Reading status ([%d] including ", (state_&DRIVESEL) ? 2 : 1);
|
||||||
|
|
||||||
// Determine the SENSE input.
|
// Determine the SENSE input.
|
||||||
uint8_t sense = 0;
|
uint8_t sense = 0x80;
|
||||||
switch(state_ & (CA2 | CA1 | CA0 | SEL)) {
|
switch(state_ & (CA2 | CA1 | CA0 | SEL)) {
|
||||||
default:
|
default:
|
||||||
printf("unknown)\n");
|
printf("unknown)\n");
|
||||||
@ -85,7 +88,6 @@ uint8_t IWM::read(int address) {
|
|||||||
|
|
||||||
case SEL: // Disk in place.
|
case SEL: // Disk in place.
|
||||||
printf("disk in place)\n");
|
printf("disk in place)\n");
|
||||||
sense = 0x80;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CA0: // Disk head stepping.
|
case CA0: // Disk head stepping.
|
||||||
|
50
Machines/Apple/Macintosh/Audio.cpp
Normal file
50
Machines/Apple/Macintosh/Audio.cpp
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
//
|
||||||
|
// Audio.cpp
|
||||||
|
// Clock Signal
|
||||||
|
//
|
||||||
|
// Created by Thomas Harte on 31/05/2019.
|
||||||
|
// Copyright © 2019 Thomas Harte. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "Audio.hpp"
|
||||||
|
|
||||||
|
using namespace Apple::Macintosh;
|
||||||
|
|
||||||
|
Audio::Audio(Concurrency::DeferringAsyncTaskQueue &task_queue) : task_queue_(task_queue) {}
|
||||||
|
|
||||||
|
// MARK: - Inputs
|
||||||
|
|
||||||
|
void Audio::post_sample(uint8_t sample) {
|
||||||
|
const auto write_pointer = sample_queue_.write_pointer.load();
|
||||||
|
// const auto pointers
|
||||||
|
|
||||||
|
const auto read_pointer = sample_queue_.read_pointer.load();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Audio::set_volume(int volume) {
|
||||||
|
task_queue_.defer([=] () {
|
||||||
|
volume_ = volume;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void Audio::set_enabled(bool on) {
|
||||||
|
task_queue_.defer([=] () {
|
||||||
|
is_enabled_ = on;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Output generation
|
||||||
|
|
||||||
|
bool Audio::is_zero_level() {
|
||||||
|
return !volume_ || !is_enabled_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Audio::set_sample_volume_range(std::int16_t range) {
|
||||||
|
volume_multiplier_ = range / 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Audio::get_samples(std::size_t number_of_samples, int16_t *target) {
|
||||||
|
// if(is_zero_level()) {
|
||||||
|
// memset(target, 0, number_of_samples * sizeof(int16_t));
|
||||||
|
// }
|
||||||
|
}
|
78
Machines/Apple/Macintosh/Audio.hpp
Normal file
78
Machines/Apple/Macintosh/Audio.hpp
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
//
|
||||||
|
// Audio.hpp
|
||||||
|
// Clock Signal
|
||||||
|
//
|
||||||
|
// Created by Thomas Harte on 31/05/2019.
|
||||||
|
// Copyright © 2019 Thomas Harte. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef Audio_hpp
|
||||||
|
#define Audio_hpp
|
||||||
|
|
||||||
|
#include "../../../Outputs/Speaker/Implementation/SampleSource.hpp"
|
||||||
|
#include "../../../Concurrency/AsyncTaskQueue.hpp"
|
||||||
|
#include "../../../ClockReceiver/ClockReceiver.hpp"
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <atomic>
|
||||||
|
|
||||||
|
namespace Apple {
|
||||||
|
namespace Macintosh {
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Implements the Macintosh's audio output hardware, using a
|
||||||
|
combination
|
||||||
|
*/
|
||||||
|
class Audio: public ::Outputs::Speaker::SampleSource {
|
||||||
|
public:
|
||||||
|
Audio(Concurrency::DeferringAsyncTaskQueue &task_queue);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Macintosh audio is (partly) sourced by the same scanning
|
||||||
|
hardware as the video; each line it collects an additional
|
||||||
|
word of memory, half of which is used for audio output.
|
||||||
|
|
||||||
|
Use this method to add a newly-collected sample to the queue.
|
||||||
|
*/
|
||||||
|
void post_sample(uint8_t sample);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Macintosh audio also separately receives an output volume
|
||||||
|
level, in the range 0 to 7.
|
||||||
|
|
||||||
|
Use this method to set the current output volume.
|
||||||
|
*/
|
||||||
|
void set_volume(int volume);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
A further factor in audio output is the on-off toggle.
|
||||||
|
*/
|
||||||
|
void set_enabled(bool on);
|
||||||
|
|
||||||
|
// to satisfy ::Outputs::Speaker (included via ::Outputs::Filter.
|
||||||
|
void get_samples(std::size_t number_of_samples, int16_t *target);
|
||||||
|
bool is_zero_level();
|
||||||
|
void set_sample_volume_range(std::int16_t range);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Concurrency::DeferringAsyncTaskQueue &task_queue_;
|
||||||
|
|
||||||
|
// A queue of fetched samples; read from by one thread,
|
||||||
|
// written to by another.
|
||||||
|
struct {
|
||||||
|
std::array<uint8_t, 2048> buffer;
|
||||||
|
std::atomic<int> read_pointer, write_pointer;
|
||||||
|
} sample_queue_;
|
||||||
|
|
||||||
|
// Stateful variables, modified from the audio generation
|
||||||
|
// thread only.
|
||||||
|
int volume_ = 0;
|
||||||
|
bool is_enabled_ = false;
|
||||||
|
|
||||||
|
std::int16_t volume_multiplier_ = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* Audio_hpp */
|
@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
|
|
||||||
|
#include "Audio.hpp"
|
||||||
#include "Keyboard.hpp"
|
#include "Keyboard.hpp"
|
||||||
#include "RealTimeClock.hpp"
|
#include "RealTimeClock.hpp"
|
||||||
#include "Video.hpp"
|
#include "Video.hpp"
|
||||||
@ -18,9 +19,10 @@
|
|||||||
|
|
||||||
//#define LOG_TRACE
|
//#define LOG_TRACE
|
||||||
|
|
||||||
#include "../../../Processors/68000/68000.hpp"
|
|
||||||
#include "../../../Components/6522/6522.hpp"
|
#include "../../../Components/6522/6522.hpp"
|
||||||
#include "../../../Components/DiskII/IWM.hpp"
|
#include "../../../Components/DiskII/IWM.hpp"
|
||||||
|
#include "../../../Outputs/Speaker/Implementation/LowpassSpeaker.hpp"
|
||||||
|
#include "../../../Processors/68000/68000.hpp"
|
||||||
|
|
||||||
#include "../../Utility/MemoryPacker.hpp"
|
#include "../../Utility/MemoryPacker.hpp"
|
||||||
|
|
||||||
@ -42,7 +44,7 @@ class ConcreteMachine:
|
|||||||
mc68000_(*this),
|
mc68000_(*this),
|
||||||
video_(ram_.data()),
|
video_(ram_.data()),
|
||||||
via_(via_port_handler_),
|
via_(via_port_handler_),
|
||||||
via_port_handler_(*this, clock_, keyboard_, video_, iwm_),
|
via_port_handler_(*this, clock_, keyboard_, video_, audio_, iwm_),
|
||||||
iwm_(CLOCK_RATE) {
|
iwm_(CLOCK_RATE) {
|
||||||
|
|
||||||
// Grab a copy of the ROM and convert it into big-endian data.
|
// Grab a copy of the ROM and convert it into big-endian data.
|
||||||
@ -62,7 +64,7 @@ class ConcreteMachine:
|
|||||||
}
|
}
|
||||||
|
|
||||||
Outputs::Speaker::Speaker *get_speaker() override {
|
Outputs::Speaker::Speaker *get_speaker() override {
|
||||||
return nullptr;
|
return &audio_.speaker;
|
||||||
}
|
}
|
||||||
|
|
||||||
void run_for(const Cycles cycles) override {
|
void run_for(const Cycles cycles) override {
|
||||||
@ -227,7 +229,14 @@ class ConcreteMachine:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void flush() {
|
void flush() {
|
||||||
|
// Flush the video before the audio queue; in a Mac the
|
||||||
|
// video is responsible for providing part of the
|
||||||
|
// audio signal, so the two aren't as distinct as in
|
||||||
|
// most machines.
|
||||||
// video_.run_for(time_since_video_update_.flush());
|
// video_.run_for(time_since_video_update_.flush());
|
||||||
|
|
||||||
|
// As above: flush audio after video.
|
||||||
|
audio_.queue.flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_rom_is_overlay(bool rom_is_overlay) {
|
void set_rom_is_overlay(bool rom_is_overlay) {
|
||||||
@ -250,10 +259,23 @@ class ConcreteMachine:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct Audio {
|
||||||
|
Concurrency::DeferringAsyncTaskQueue queue;
|
||||||
|
Apple::Macintosh::Audio audio;
|
||||||
|
Outputs::Speaker::LowpassSpeaker<Apple::Macintosh::Audio> speaker;
|
||||||
|
HalfCycles time_since_update;
|
||||||
|
|
||||||
|
Audio() : audio(queue), speaker(audio) {}
|
||||||
|
|
||||||
|
void flush() {
|
||||||
|
speaker.run_for(queue, time_since_update.flush_cycles());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
class VIAPortHandler: public MOS::MOS6522::PortHandler {
|
class VIAPortHandler: public MOS::MOS6522::PortHandler {
|
||||||
public:
|
public:
|
||||||
VIAPortHandler(ConcreteMachine &machine, RealTimeClock &clock, Keyboard &keyboard, Video &video, IWM &iwm) :
|
VIAPortHandler(ConcreteMachine &machine, RealTimeClock &clock, Keyboard &keyboard, Video &video, Audio &audio, IWM &iwm) :
|
||||||
machine_(machine), clock_(clock), keyboard_(keyboard), video_(video), iwm_(iwm) {}
|
machine_(machine), clock_(clock), keyboard_(keyboard), video_(video), audio_(audio), iwm_(iwm) {}
|
||||||
|
|
||||||
using Port = MOS::MOS6522::Port;
|
using Port = MOS::MOS6522::Port;
|
||||||
using Line = MOS::MOS6522::Line;
|
using Line = MOS::MOS6522::Line;
|
||||||
@ -274,15 +296,16 @@ class ConcreteMachine:
|
|||||||
b3: 0 = use alternate sound buffer, 1 = use ordinary sound buffer
|
b3: 0 = use alternate sound buffer, 1 = use ordinary sound buffer
|
||||||
b2–b0: audio output volume
|
b2–b0: audio output volume
|
||||||
*/
|
*/
|
||||||
// printf("6522 A: %02x\n", value);
|
|
||||||
|
|
||||||
iwm_.flush();
|
iwm_.flush();
|
||||||
iwm_.iwm.set_select(!(value & 0x20));
|
iwm_.iwm.set_select(!(value & 0x20));
|
||||||
|
|
||||||
machine_.set_use_alternate_screen_buffer(!(value & 0x40));
|
machine_.set_use_alternate_screen_buffer(!(value & 0x40));
|
||||||
machine_.set_rom_is_overlay(!!(value & 0x10));
|
machine_.set_rom_is_overlay(!!(value & 0x10));
|
||||||
|
|
||||||
// TODO: alternate sound buffer, and audio output volume.
|
audio_.flush();
|
||||||
|
audio_.audio.set_volume(value & 7);
|
||||||
|
|
||||||
|
// TODO: alternate sound buffer.
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Port::B:
|
case Port::B:
|
||||||
@ -300,7 +323,8 @@ class ConcreteMachine:
|
|||||||
if(value & 0x4) clock_.abort();
|
if(value & 0x4) clock_.abort();
|
||||||
else clock_.set_input(!!(value & 0x2), !!(value & 0x1));
|
else clock_.set_input(!!(value & 0x2), !!(value & 0x1));
|
||||||
|
|
||||||
// TODO: sound enabled/disabled.
|
audio_.flush();
|
||||||
|
audio_.audio.set_enabled(!!(value & 0x80));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -336,6 +360,7 @@ class ConcreteMachine:
|
|||||||
RealTimeClock &clock_;
|
RealTimeClock &clock_;
|
||||||
Keyboard &keyboard_;
|
Keyboard &keyboard_;
|
||||||
Video &video_;
|
Video &video_;
|
||||||
|
Audio &audio_;
|
||||||
IWM &iwm_;
|
IWM &iwm_;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -343,7 +368,9 @@ class ConcreteMachine:
|
|||||||
std::array<uint16_t, 64*1024> ram_;
|
std::array<uint16_t, 64*1024> ram_;
|
||||||
|
|
||||||
CPU::MC68000::Processor<ConcreteMachine, true> mc68000_;
|
CPU::MC68000::Processor<ConcreteMachine, true> mc68000_;
|
||||||
|
|
||||||
Video video_;
|
Video video_;
|
||||||
|
Audio audio_;
|
||||||
|
|
||||||
RealTimeClock clock_;
|
RealTimeClock clock_;
|
||||||
Keyboard keyboard_;
|
Keyboard keyboard_;
|
||||||
|
@ -170,7 +170,7 @@ class VIAPortHandler: public MOS::MOS6522::IRQDelegatePortHandler {
|
|||||||
/*!
|
/*!
|
||||||
Advances time. This class manages the AY's concept of time to permit updating-on-demand.
|
Advances time. This class manages the AY's concept of time to permit updating-on-demand.
|
||||||
*/
|
*/
|
||||||
inline void run_for(const Cycles cycles) {
|
inline void run_for(const HalfCycles cycles) {
|
||||||
cycles_since_ay_update_ += cycles;
|
cycles_since_ay_update_ += cycles;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -182,11 +182,11 @@ class VIAPortHandler: public MOS::MOS6522::IRQDelegatePortHandler {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
void update_ay() {
|
void update_ay() {
|
||||||
speaker_.run_for(audio_queue_, cycles_since_ay_update_.flush());
|
speaker_.run_for(audio_queue_, cycles_since_ay_update_.flush_cycles());
|
||||||
}
|
}
|
||||||
bool ay_bdir_ = false;
|
bool ay_bdir_ = false;
|
||||||
bool ay_bc1_ = false;
|
bool ay_bc1_ = false;
|
||||||
Cycles cycles_since_ay_update_;
|
HalfCycles cycles_since_ay_update_;
|
||||||
|
|
||||||
Concurrency::DeferringAsyncTaskQueue &audio_queue_;
|
Concurrency::DeferringAsyncTaskQueue &audio_queue_;
|
||||||
GI::AY38910::AY38910 &ay8910_;
|
GI::AY38910::AY38910 &ay8910_;
|
||||||
@ -434,7 +434,6 @@ template <Analyser::Static::Oric::Target::DiskInterface disk_interface> class Co
|
|||||||
}
|
}
|
||||||
|
|
||||||
via_.run_for(Cycles(1));
|
via_.run_for(Cycles(1));
|
||||||
via_port_handler_.run_for(Cycles(1));
|
|
||||||
tape_player_.run_for(Cycles(1));
|
tape_player_.run_for(Cycles(1));
|
||||||
switch(disk_interface) {
|
switch(disk_interface) {
|
||||||
default: break;
|
default: break;
|
||||||
@ -456,7 +455,7 @@ template <Analyser::Static::Oric::Target::DiskInterface disk_interface> class Co
|
|||||||
|
|
||||||
forceinline void flush() {
|
forceinline void flush() {
|
||||||
update_video();
|
update_video();
|
||||||
via_port_handler_.flush();
|
via_.flush();
|
||||||
flush_diskii();
|
flush_diskii();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -296,6 +296,7 @@
|
|||||||
4B924E991E74D22700B76AF1 /* AtariStaticAnalyserTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B924E981E74D22700B76AF1 /* AtariStaticAnalyserTests.mm */; };
|
4B924E991E74D22700B76AF1 /* AtariStaticAnalyserTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B924E981E74D22700B76AF1 /* AtariStaticAnalyserTests.mm */; };
|
||||||
4B9252CE1E74D28200B76AF1 /* Atari ROMs in Resources */ = {isa = PBXBuildFile; fileRef = 4B9252CD1E74D28200B76AF1 /* Atari ROMs */; };
|
4B9252CE1E74D28200B76AF1 /* Atari ROMs in Resources */ = {isa = PBXBuildFile; fileRef = 4B9252CD1E74D28200B76AF1 /* Atari ROMs */; };
|
||||||
4B92EACA1B7C112B00246143 /* 6502TimingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B92EAC91B7C112B00246143 /* 6502TimingTests.swift */; };
|
4B92EACA1B7C112B00246143 /* 6502TimingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B92EAC91B7C112B00246143 /* 6502TimingTests.swift */; };
|
||||||
|
4B9378E422A199C600973513 /* Audio.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B9378E222A199C600973513 /* Audio.cpp */; };
|
||||||
4B98A05E1FFAD3F600ADF63B /* CSROMFetcher.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B98A05D1FFAD3F600ADF63B /* CSROMFetcher.mm */; };
|
4B98A05E1FFAD3F600ADF63B /* CSROMFetcher.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B98A05D1FFAD3F600ADF63B /* CSROMFetcher.mm */; };
|
||||||
4B98A05F1FFAD62400ADF63B /* CSROMFetcher.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B98A05D1FFAD3F600ADF63B /* CSROMFetcher.mm */; };
|
4B98A05F1FFAD62400ADF63B /* CSROMFetcher.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B98A05D1FFAD3F600ADF63B /* CSROMFetcher.mm */; };
|
||||||
4B98A0611FFADCDE00ADF63B /* MSXStaticAnalyserTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B98A0601FFADCDE00ADF63B /* MSXStaticAnalyserTests.mm */; };
|
4B98A0611FFADCDE00ADF63B /* MSXStaticAnalyserTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B98A0601FFADCDE00ADF63B /* MSXStaticAnalyserTests.mm */; };
|
||||||
@ -1031,6 +1032,8 @@
|
|||||||
4B924E981E74D22700B76AF1 /* AtariStaticAnalyserTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = AtariStaticAnalyserTests.mm; sourceTree = "<group>"; };
|
4B924E981E74D22700B76AF1 /* AtariStaticAnalyserTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = AtariStaticAnalyserTests.mm; sourceTree = "<group>"; };
|
||||||
4B9252CD1E74D28200B76AF1 /* Atari ROMs */ = {isa = PBXFileReference; lastKnownFileType = folder; path = "Atari ROMs"; sourceTree = "<group>"; };
|
4B9252CD1E74D28200B76AF1 /* Atari ROMs */ = {isa = PBXFileReference; lastKnownFileType = folder; path = "Atari ROMs"; sourceTree = "<group>"; };
|
||||||
4B92EAC91B7C112B00246143 /* 6502TimingTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = 6502TimingTests.swift; sourceTree = "<group>"; };
|
4B92EAC91B7C112B00246143 /* 6502TimingTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = 6502TimingTests.swift; sourceTree = "<group>"; };
|
||||||
|
4B9378E222A199C600973513 /* Audio.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Audio.cpp; sourceTree = "<group>"; };
|
||||||
|
4B9378E322A199C600973513 /* Audio.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Audio.hpp; sourceTree = "<group>"; };
|
||||||
4B95FA9C1F11893B0008E395 /* ZX8081OptionsPanel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ZX8081OptionsPanel.swift; sourceTree = "<group>"; };
|
4B95FA9C1F11893B0008E395 /* ZX8081OptionsPanel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ZX8081OptionsPanel.swift; sourceTree = "<group>"; };
|
||||||
4B961408222760E0001A7BF2 /* Screenshot.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Screenshot.hpp; sourceTree = "<group>"; };
|
4B961408222760E0001A7BF2 /* Screenshot.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Screenshot.hpp; sourceTree = "<group>"; };
|
||||||
4B98A05C1FFAD3F600ADF63B /* CSROMFetcher.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = CSROMFetcher.hpp; sourceTree = "<group>"; };
|
4B98A05C1FFAD3F600ADF63B /* CSROMFetcher.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = CSROMFetcher.hpp; sourceTree = "<group>"; };
|
||||||
@ -3065,12 +3068,14 @@
|
|||||||
4BCE0057227CFFCA000CA200 /* Macintosh */ = {
|
4BCE0057227CFFCA000CA200 /* Macintosh */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
4B9378E222A199C600973513 /* Audio.cpp */,
|
||||||
4BCE0058227CFFCA000CA200 /* Macintosh.cpp */,
|
4BCE0058227CFFCA000CA200 /* Macintosh.cpp */,
|
||||||
4BCE005E227D39AB000CA200 /* Video.cpp */,
|
4BCE005E227D39AB000CA200 /* Video.cpp */,
|
||||||
|
4B9378E322A199C600973513 /* Audio.hpp */,
|
||||||
|
4BDB3D8522833321002D3CEE /* Keyboard.hpp */,
|
||||||
4BCE0059227CFFCA000CA200 /* Macintosh.hpp */,
|
4BCE0059227CFFCA000CA200 /* Macintosh.hpp */,
|
||||||
4BD0692B22828A2D00D2A54F /* RealTimeClock.hpp */,
|
4BD0692B22828A2D00D2A54F /* RealTimeClock.hpp */,
|
||||||
4BCE005F227D39AB000CA200 /* Video.hpp */,
|
4BCE005F227D39AB000CA200 /* Video.hpp */,
|
||||||
4BDB3D8522833321002D3CEE /* Keyboard.hpp */,
|
|
||||||
);
|
);
|
||||||
path = Macintosh;
|
path = Macintosh;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -3254,11 +3259,11 @@
|
|||||||
4BF660691F281573002CB053 /* ClockReceiver */ = {
|
4BF660691F281573002CB053 /* ClockReceiver */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
4B8A7E85212F988200F2BBC6 /* ClockDeferrer.hpp */,
|
||||||
|
4BB146C61F49D7D700253439 /* ClockingHintSource.hpp */,
|
||||||
4BF6606A1F281573002CB053 /* ClockReceiver.hpp */,
|
4BF6606A1F281573002CB053 /* ClockReceiver.hpp */,
|
||||||
4BB06B211F316A3F00600C7A /* ForceInline.hpp */,
|
4BB06B211F316A3F00600C7A /* ForceInline.hpp */,
|
||||||
4BB146C61F49D7D700253439 /* ClockingHintSource.hpp */,
|
|
||||||
4B449C942063389900A095C8 /* TimeTypes.hpp */,
|
4B449C942063389900A095C8 /* TimeTypes.hpp */,
|
||||||
4B8A7E85212F988200F2BBC6 /* ClockDeferrer.hpp */,
|
|
||||||
);
|
);
|
||||||
name = ClockReceiver;
|
name = ClockReceiver;
|
||||||
path = ../../ClockReceiver;
|
path = ../../ClockReceiver;
|
||||||
@ -3905,6 +3910,7 @@
|
|||||||
4B2BFC5F1D613E0200BA3AA9 /* TapePRG.cpp in Sources */,
|
4B2BFC5F1D613E0200BA3AA9 /* TapePRG.cpp in Sources */,
|
||||||
4BC9DF4F1D04691600F44158 /* 6560.cpp in Sources */,
|
4BC9DF4F1D04691600F44158 /* 6560.cpp in Sources */,
|
||||||
4B59199C1DAC6C46005BB85C /* OricTAP.cpp in Sources */,
|
4B59199C1DAC6C46005BB85C /* OricTAP.cpp in Sources */,
|
||||||
|
4B9378E422A199C600973513 /* Audio.cpp in Sources */,
|
||||||
4B89451E201967B4007DE474 /* Tape.cpp in Sources */,
|
4B89451E201967B4007DE474 /* Tape.cpp in Sources */,
|
||||||
4BAF2B4E2004580C00480230 /* DMK.cpp in Sources */,
|
4BAF2B4E2004580C00480230 /* DMK.cpp in Sources */,
|
||||||
4BB697CE1D4BA44400248BDF /* CommodoreGCR.cpp in Sources */,
|
4BB697CE1D4BA44400248BDF /* CommodoreGCR.cpp in Sources */,
|
||||||
|
Loading…
Reference in New Issue
Block a user