mirror of
https://github.com/TomHarte/CLK.git
synced 2024-12-28 07:29:45 +00:00
Attempts to tie an intelligent keyboard to the other end of its serial line.
This commit is contained in:
parent
b69180ba01
commit
0fd8813ddb
@ -57,6 +57,7 @@ void ACIA::write(int address, uint8_t value) {
|
||||
} else {
|
||||
if((value&3) == 3) {
|
||||
transmit.reset_writing();
|
||||
transmit.write(true);
|
||||
request_to_send.reset_writing();
|
||||
} else {
|
||||
switch(value & 3) {
|
||||
|
@ -19,14 +19,25 @@ void Line::advance_writer(int cycles) {
|
||||
while(!events_.empty()) {
|
||||
if(events_.front().delay < cycles) {
|
||||
cycles -= events_.front().delay;
|
||||
write_cycles_since_delegate_call_ += events_.front().delay;
|
||||
const auto old_level = level_;
|
||||
|
||||
auto iterator = events_.begin() + 1;
|
||||
while(iterator != events_.end() && iterator->type != Event::Delay) {
|
||||
level_ = iterator->type == Event::SetHigh;
|
||||
++iterator;
|
||||
}
|
||||
events_.erase(events_.begin(), iterator);
|
||||
|
||||
if(old_level != level_) {
|
||||
if(read_delegate_) {
|
||||
read_delegate_->serial_line_did_change_output(this, Storage::Time(write_cycles_since_delegate_call_, clock_rate_), level_);
|
||||
write_cycles_since_delegate_call_ = 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
events_.front().delay -= cycles;
|
||||
write_cycles_since_delegate_call_ += cycles;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -50,6 +61,7 @@ void Line::write(int cycles, int count, int levels) {
|
||||
events_[event].type = Event::Delay;
|
||||
events_[event].delay = cycles;
|
||||
events_[event+1].type = (levels&1) ? Event::SetHigh : Event::SetLow;
|
||||
levels >>= 1;
|
||||
event += 2;
|
||||
}
|
||||
}
|
||||
@ -66,10 +78,22 @@ void Line::reset_writing() {
|
||||
void Line::flush_writing() {
|
||||
remaining_delays_ = 0;
|
||||
for(const auto &event : events_) {
|
||||
bool new_level = level_;
|
||||
switch(event.type) {
|
||||
default: break;
|
||||
case Event::SetHigh: level_ = true; break;
|
||||
case Event::SetLow: level_ = false; break;
|
||||
case Event::SetHigh: new_level = true; break;
|
||||
case Event::SetLow: new_level = false; break;
|
||||
case Event::Delay:
|
||||
write_cycles_since_delegate_call_ += event.delay;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(new_level != level_) {
|
||||
level_ = new_level;
|
||||
if(read_delegate_) {
|
||||
read_delegate_->serial_line_did_change_output(this, Storage::Time(write_cycles_since_delegate_call_, clock_rate_), level_);
|
||||
write_cycles_since_delegate_call_ = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
events_.clear();
|
||||
@ -78,3 +102,8 @@ void Line::flush_writing() {
|
||||
bool Line::read() {
|
||||
return level_;
|
||||
}
|
||||
|
||||
void Line::set_read_delegate(ReadDelegate *delegate) {
|
||||
read_delegate_ = delegate;
|
||||
write_cycles_since_delegate_call_ = 0;
|
||||
}
|
||||
|
@ -10,6 +10,7 @@
|
||||
#define SerialPort_hpp
|
||||
|
||||
#include <vector>
|
||||
#include "../../Storage/Storage.hpp"
|
||||
|
||||
namespace Serial {
|
||||
|
||||
@ -53,6 +54,11 @@ class Line {
|
||||
/// @returns The instantaneous level of this line.
|
||||
bool read();
|
||||
|
||||
struct ReadDelegate {
|
||||
virtual void serial_line_did_change_output(Line *line, Storage::Time time_since_last_change, bool new_level) = 0;
|
||||
};
|
||||
void set_read_delegate(ReadDelegate *delegate);
|
||||
|
||||
private:
|
||||
struct Event {
|
||||
enum Type {
|
||||
@ -64,6 +70,9 @@ class Line {
|
||||
int remaining_delays_ = 0;
|
||||
bool level_ = false;
|
||||
int clock_rate_ = 0;
|
||||
|
||||
ReadDelegate *read_delegate_ = nullptr;
|
||||
int write_cycles_since_delegate_call_ = 0;
|
||||
};
|
||||
|
||||
/*!
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "../../ClockReceiver/ForceInline.hpp"
|
||||
|
||||
#include "../../Outputs/Speaker/Implementation/LowpassSpeaker.hpp"
|
||||
#include "../../Outputs/Log.hpp"
|
||||
|
||||
#include "../Utility/MemoryPacker.hpp"
|
||||
#include "../Utility/MemoryFuzzer.hpp"
|
||||
@ -30,8 +31,50 @@ namespace ST {
|
||||
|
||||
const int CLOCK_RATE = 8000000;
|
||||
|
||||
using Target = Analyser::Static::Target;
|
||||
/*!
|
||||
A receiver for the Atari ST's "intelligent keyboard" commands, which actually cover
|
||||
keyboard input and output and mouse handling.
|
||||
*/
|
||||
class IntelligentKeyboard:
|
||||
public Serial::Line::ReadDelegate {
|
||||
public:
|
||||
IntelligentKeyboard(Serial::Line &input, Serial::Line &output) : output_line_(output) {
|
||||
input.set_read_delegate(this);
|
||||
}
|
||||
|
||||
void serial_line_did_change_output(Serial::Line *, Storage::Time time_since_last_change, bool new_level) final {
|
||||
// Figure out how many bits have passed. TODO: in fixed point?
|
||||
const float number_of_bits = time_since_last_change.get<float>() * 7812.5f + bit_offset_;
|
||||
bit_offset_ = fmodf(number_of_bits, 1.0f);
|
||||
|
||||
int bits_remaining = int(number_of_bits);
|
||||
while(bits_remaining--) {
|
||||
if(!bit_count_) {
|
||||
// Check for a potential start bit.
|
||||
if(!new_level) {
|
||||
bit_count_ = 10;
|
||||
command_ = 0;
|
||||
}
|
||||
} else {
|
||||
command_ >>= 1;
|
||||
command_ |= new_level ? 0 : 0x200;
|
||||
--bit_count_;
|
||||
|
||||
if(!bit_count_) {
|
||||
LOG("[IKBD] Should perform " << PADHEX(2) << ((command_ >> 1) & 0xff));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
int bit_count_ = 0;
|
||||
int command_ = 0;
|
||||
Serial::Line &output_line_;
|
||||
float bit_offset_ = 0.0f;
|
||||
};
|
||||
|
||||
using Target = Analyser::Static::Target;
|
||||
class ConcreteMachine:
|
||||
public Atari::ST::Machine,
|
||||
public CPU::MC68000::BusHandler,
|
||||
@ -42,7 +85,8 @@ class ConcreteMachine:
|
||||
keyboard_acia_(Cycles(500000)),
|
||||
midi_acia_(Cycles(500000)),
|
||||
ay_(audio_queue_),
|
||||
speaker_(ay_) {
|
||||
speaker_(ay_),
|
||||
ikbd_(keyboard_acia_->transmit, keyboard_acia_->receive) {
|
||||
set_clock_rate(CLOCK_RATE);
|
||||
speaker_.set_input_rate(CLOCK_RATE / 4);
|
||||
|
||||
@ -380,6 +424,8 @@ class ConcreteMachine:
|
||||
Outputs::Speaker::LowpassSpeaker<GI::AY38910::AY38910> speaker_;
|
||||
HalfCycles cycles_since_audio_update_;
|
||||
|
||||
IntelligentKeyboard ikbd_;
|
||||
|
||||
std::vector<uint16_t> ram_;
|
||||
std::vector<uint16_t> rom_;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user