mirror of
https://github.com/TomHarte/CLK.git
synced 2026-04-19 19:16:34 +00:00
Attempt to reformulate keyboard controller.
This commit is contained in:
@@ -14,6 +14,8 @@
|
||||
|
||||
#include "Analyser/Static/PCCompatible/Target.hpp"
|
||||
|
||||
extern bool should_log;
|
||||
|
||||
namespace PCCompatible {
|
||||
|
||||
/*!
|
||||
@@ -123,25 +125,29 @@ public:
|
||||
const Analyser::Static::PCCompatible::Target::VideoAdaptor adaptor
|
||||
) : pics_(pics), speaker_(speaker) {
|
||||
if(adaptor == Analyser::Static::PCCompatible::Target::VideoAdaptor::MDA) {
|
||||
port_input_ |= 0x40;
|
||||
switches_ |= 0x40;
|
||||
}
|
||||
}
|
||||
|
||||
void run_for(const Cycles cycles) {
|
||||
instruction_count_ += cycles.as<int>();
|
||||
if(!write_delay_) return;
|
||||
write_delay_ -= cycles.as<int>();
|
||||
if(write_delay_ <= 0) {
|
||||
write_delay_ = 0;
|
||||
|
||||
if(!perform_delay_) {
|
||||
return;
|
||||
}
|
||||
|
||||
perform_delay_ -= cycles.as<int>();
|
||||
if(perform_delay_ <= 0) {
|
||||
perform_delay_ = 0;
|
||||
perform_command();
|
||||
}
|
||||
}
|
||||
|
||||
void post(const uint8_t value) {
|
||||
input_ = value;
|
||||
has_input_ = true;
|
||||
command_phase_ = CommandPhase::WaitingForCommand;
|
||||
pics_.pic[0].template apply_edge<1>(true);
|
||||
log_.info().append("Posting %02x", value);
|
||||
output_ = value;
|
||||
has_output_ = true;
|
||||
pics_.pic[0].template apply_edge<1>(true); // TODO: verify.
|
||||
}
|
||||
|
||||
void write(const uint16_t port, const uint8_t value) {
|
||||
@@ -151,10 +157,11 @@ public:
|
||||
break;
|
||||
|
||||
case 0x0060:
|
||||
// log_.error().append("Keyboard parameter set to %02x", value);
|
||||
output_ = value;
|
||||
has_output_ = true;
|
||||
write_delay_ = 10;
|
||||
log_.error().append("Keyboard parameter set to %02x", value);
|
||||
phase_ = Phase::Data;
|
||||
input_ = value;
|
||||
has_input_ = true;
|
||||
perform_command();
|
||||
break;
|
||||
|
||||
case 0x0061:
|
||||
@@ -166,15 +173,13 @@ public:
|
||||
break;
|
||||
|
||||
case 0x0064:
|
||||
// log_.info().append("AT keyboard command %04x", value);
|
||||
phase_ = Phase::Command;
|
||||
command_ = value;
|
||||
has_command_ = true;
|
||||
command_phase_ = CommandPhase::WaitingForData;
|
||||
has_input_ = false;
|
||||
perform_delay_ = performance_delay(command_);
|
||||
|
||||
write_delay_ = performance_delay(command_);
|
||||
if(!write_delay_) {
|
||||
perform_command();
|
||||
}
|
||||
perform_command();
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -186,9 +191,9 @@ public:
|
||||
break;
|
||||
|
||||
case 0x0060:
|
||||
log_.error().append("Read from keyboard controller of %02x", input_);
|
||||
has_input_ = false;
|
||||
return input_;
|
||||
log_.error().append("Read from keyboard controller of %02x", output_);
|
||||
has_output_ = false;
|
||||
return output_;
|
||||
|
||||
case 0x0061:
|
||||
// In a real machine bit 4 toggles as a function of memory refresh and some BIOSes
|
||||
@@ -210,10 +215,10 @@ public:
|
||||
// b0 = 1 => 'output' data is full (i.e. reading from 0x60 now makes sense — output is to PC).
|
||||
const uint8_t status =
|
||||
0x10 |
|
||||
(command_phase_ == CommandPhase::WaitingForData ? 0x08 : 0x00) |
|
||||
(is_tested_ ? 0x04 : 0x00) |
|
||||
(has_output_ ? 0x02 : 0x00) |
|
||||
(has_input_ ? 0x01 : 0x00);
|
||||
(phase_ == Phase::Data ? 0x08 : 0x00) |
|
||||
(is_tested_ ? 0x04 : 0x00) |
|
||||
(has_input_ ? 0x02 : 0x00) |
|
||||
(has_output_ ? 0x01 : 0x00);
|
||||
log_.error().append("Reading status: %02x", status);
|
||||
return status;
|
||||
}
|
||||
@@ -239,30 +244,22 @@ private:
|
||||
}
|
||||
|
||||
switch(command) {
|
||||
case 0xaa: return 5;
|
||||
case 0xaa: return 15;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void perform_command() {
|
||||
// Wait for a command.
|
||||
if(!has_command_) return;
|
||||
|
||||
// Wait for a parameter if one is needed.
|
||||
if(requires_parameter(command_) && !has_output_) {
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
auto info = log_.info();
|
||||
info.append("Keyboard command: %02x", command_);
|
||||
if(has_output_) {
|
||||
info.append(" / %02x", output_);
|
||||
}
|
||||
}
|
||||
// Wait for a complete command.
|
||||
if(
|
||||
!has_command_ ||
|
||||
perform_delay_ ||
|
||||
(requires_parameter(command_) && !has_input_)
|
||||
) return;
|
||||
log_.info().append("Keyboard command: %02x", command_).append_if(has_input_, " / %02x", input_);
|
||||
|
||||
// Consume command and parameter, and execute.
|
||||
has_command_ = has_output_ = false;
|
||||
has_command_ = has_input_ = false;
|
||||
|
||||
switch(command_) {
|
||||
default:
|
||||
@@ -293,7 +290,7 @@ private:
|
||||
break;
|
||||
|
||||
case 0xc0: // Read input port.
|
||||
post(port_input_);
|
||||
post(switches_);
|
||||
break;
|
||||
|
||||
case 0xf0: case 0xf1: case 0xf2: case 0xf3:
|
||||
@@ -307,39 +304,40 @@ private:
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
command_phase_ = CommandPhase::WaitingForCommand;
|
||||
}
|
||||
|
||||
Log::Logger<Log::Source::PCCompatible> log_;
|
||||
Log::Logger<Log::Source::Keyboard> log_;
|
||||
|
||||
PICs<model> &pics_;
|
||||
Speaker &speaker_;
|
||||
CPUControl<model> *cpu_control_ = nullptr;
|
||||
|
||||
// Strongly coupled to specific code in the 5170 BIOS, this provides a grossly-inaccurate
|
||||
// linkage between execution speed (-ish) and DRAM refresh. An unambguous nonsense.
|
||||
int instruction_count_ = 0;
|
||||
|
||||
bool has_input_ = false;
|
||||
uint8_t input_;
|
||||
bool has_output_ = false;
|
||||
uint8_t output_;
|
||||
bool has_command_ = false;
|
||||
uint8_t command_;
|
||||
|
||||
// bit 7 = 0 keyboard inhibited
|
||||
// bit 6 = 0 CGA, else MDA
|
||||
// bit 5 = 0 manufacturing jumper installed
|
||||
// bit 4 = 0 system RAM 512K, else 640K
|
||||
// bit 3-0 reserved
|
||||
uint8_t port_input_ = 0b1011'0000;
|
||||
bool has_input_ = false;
|
||||
bool has_output_ = false;
|
||||
bool has_command_ = false;
|
||||
|
||||
int write_delay_ = 0;
|
||||
// bit 7 = 0 keyboard inhibited
|
||||
// bit 6 = 0 CGA, else MDA
|
||||
// bit 5 = 0 manufacturing jumper installed
|
||||
// bit 4 = 0 system RAM 512K, else 640K
|
||||
// bit 3-0 reserved
|
||||
uint8_t switches_ = 0b1011'0000;
|
||||
|
||||
int perform_delay_ = 0;
|
||||
|
||||
bool is_tested_ = false;
|
||||
enum class CommandPhase {
|
||||
WaitingForCommand,
|
||||
WaitingForData,
|
||||
} command_phase_ = CommandPhase::WaitingForCommand;
|
||||
enum class Phase {
|
||||
Command,
|
||||
Data,
|
||||
} phase_ = Phase::Command;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -904,7 +904,7 @@ public:
|
||||
}
|
||||
|
||||
void set_key_state(const uint16_t key, const bool is_pressed) final {
|
||||
keyboard_.post(uint8_t(key | (is_pressed ? 0x00 : 0x80)));
|
||||
// keyboard_.post(uint8_t(key | (is_pressed ? 0x00 : 0x80)));
|
||||
}
|
||||
|
||||
// MARK: - Activity::Source.
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
#include <ctime>
|
||||
|
||||
//extern bool should_log;
|
||||
extern bool should_log;
|
||||
|
||||
namespace PCCompatible {
|
||||
|
||||
@@ -44,9 +44,9 @@ public:
|
||||
default:
|
||||
if(ram_selected()) {
|
||||
// printf("RTC: %02x <- %zu\n", ram_[ram_address()], ram_address());
|
||||
// if(ram_address() == 1 && ram_[1] == 6) {
|
||||
// should_log = true;
|
||||
// }
|
||||
if(ram_address() == 1 && ram_[1] == 6) { // Catch reset after passing protected mode test.
|
||||
should_log = true;
|
||||
}
|
||||
return ram_[ram_address()];
|
||||
}
|
||||
return 0xff;
|
||||
|
||||
Reference in New Issue
Block a user