1
0
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:
Thomas Harte
2025-08-20 17:17:54 -04:00
parent d47332adf5
commit dfd521e938
3 changed files with 64 additions and 66 deletions
+59 -61
View File
@@ -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;
};
}
+1 -1
View File
@@ -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.
+4 -4
View File
@@ -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;