1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-09-29 16:55:59 +00:00

Eliminate comparison costs.

This commit is contained in:
Thomas Harte 2024-05-18 22:16:58 -04:00
parent 26375dc023
commit 3be5d60b1e
5 changed files with 103 additions and 75 deletions

View File

@ -147,9 +147,6 @@ Analyser::Static::TargetList Analyser::Static::Acorn::GetTargets(const Media &me
// Archimedes options, implicitly: ADFS, non-Hugo.
targetArchimedes->media.disks = media.disks;
// Always try a shift-restart; it's worth a go.
targetArchimedes->should_shift_restart = true;
// Also look for the best possible startup program name, if it can be discerned.
for(const auto &file: adfs_catalogue->files) {
// Skip files that would have been caught by shift-restart if suitable.

View File

@ -35,7 +35,6 @@ struct ElectronTarget: public ::Analyser::Static::Target, public Reflection::Str
};
struct ArchimedesTarget: public ::Analyser::Static::Target, public Reflection::StructImpl<ArchimedesTarget> {
bool should_shift_restart = false;
std::string main_program;
ArchimedesTarget() : Analyser::Static::Target(Machine::Archimedes) {}

View File

@ -127,6 +127,8 @@ class ConcreteMachine:
if(!target.media.disks.empty()) {
autoload_phase_ = AutoloadPhase::WaitingForStartup;
target_program_ = target.main_program;
printf("Will seek %s?\n", target_program_.c_str());
}
fill_pipeline(0);
@ -234,10 +236,10 @@ class ConcreteMachine:
cursor_actions_.push_back(CursorAction::button(0, true));
cursor_actions_.push_back(CursorAction::wait(12'000'000));
cursor_actions_.push_back(CursorAction::button(0, false));
cursor_actions_.push_back(CursorAction::move_to(64, 32));
cursor_actions_.push_back(CursorAction::set_phase(
target_program_.empty() ? AutoloadPhase::Ended : AutoloadPhase::WaitingForDiskContents)
);
cursor_actions_.push_back(CursorAction::move_to(64, 36));
}
// TODO: spot potential addition of extra program icon.
@ -255,6 +257,7 @@ class ConcreteMachine:
desc = get_string(address + 20, flags & (1 << 8));
}
printf("%s == %s?\n", desc.c_str(), target_program_.c_str());
if(desc == target_program_) {
uint32_t x1, y1, x2, y2;
executor_.bus.read(address + 0, x1, false);
@ -265,10 +268,10 @@ class ConcreteMachine:
autoload_phase_ = AutoloadPhase::OpeningProgram;
// Some default icon sizing assumptions are baked in here.
const auto x_target = target_window_[0] + static_cast<int32_t>(x1) + 200;
const auto x_target = target_window_[0] + (static_cast<int32_t>(x1) + static_cast<int32_t>(x2)) / 2;
const auto y_target = target_window_[1] + static_cast<int32_t>(y1) + 24;
cursor_actions_.push_back(CursorAction::move_to(
x_target >> 2,
x_target >> 1,
256 - (y_target >> 2)
));
cursor_actions_.push_back(CursorAction::button(0, true));
@ -346,7 +349,7 @@ class ConcreteMachine:
// A measure of where within the tip lies within
// the default RISC OS cursor.
constexpr int ActionPointOffset = 20;
constexpr int MaxStep = 8;
constexpr int MaxStep = 24;
const auto position = executor_.bus.video().cursor_location();
if(!position) break;
@ -449,9 +452,7 @@ class ConcreteMachine:
Archimedes::KeyboardMapper keyboard_mapper_;
void set_key_state(uint16_t key, bool is_pressed) override {
const int row = Archimedes::KeyboardMapper::row(key);
const int column = Archimedes::KeyboardMapper::column(key);
executor_.bus.keyboard().set_key_state(row, column, is_pressed);
executor_.bus.keyboard().set_key_state(key, is_pressed);
}
// MARK: - MouseMachine.

View File

@ -13,14 +13,70 @@
#include "../../../Outputs/Log.hpp"
#include "../../../Inputs/Mouse.hpp"
#include <bitset>
namespace Archimedes {
namespace {
constexpr uint16_t map(int row, int column) {
return static_cast<uint16_t>((row << 4) | column);
}
constexpr uint8_t row(uint16_t key) {
return static_cast<uint8_t>(key >> 4);
}
constexpr uint8_t column(uint16_t key) {
return static_cast<uint8_t>(key & 0xf);
}
}
struct Key {
/// Named key codes that the machine wlll accept directly.
enum Value: uint16_t {
Escape = map(0, 0), F1 = map(0, 1), F2 = map(0, 2), F3 = map(0, 3),
F4 = map(0, 4), F5 = map(0, 5), F6 = map(0, 6), F7 = map(0, 7),
F8 = map(0, 8), F9 = map(0, 9), F10 = map(0, 10), F11 = map(0, 11),
F12 = map(0, 12), Print = map(0, 13), Scroll = map(0, 14), Break = map(0, 15),
Tilde = map(1, 0), k1 = map(1, 1), k2 = map(1, 2), k3 = map(1, 3),
k4 = map(1, 4), k5 = map(1, 5), k6 = map(1, 6), k7 = map(1, 7),
k8 = map(1, 8), k9 = map(1, 9), k0 = map(1, 10), Hyphen = map(1, 11),
Equals = map(1, 12), GBPound = map(1, 13), Backspace = map(1, 14), Insert = map(1, 15),
Home = map(2, 0), PageUp = map(2, 1), NumLock = map(2, 2), KeypadSlash = map(2, 3),
KeypadAsterisk = map(2, 4), KeypadHash = map(2, 5), Tab = map(2, 6), Q = map(2, 7),
W = map(2, 8), E = map(2, 9), R = map(2, 10), T = map(2, 11),
Y = map(2, 12), U = map(2, 13), I = map(2, 14), O = map(2, 15),
P = map(3, 0), OpenSquareBracket = map(3, 1), CloseSquareBracket = map(3, 2), Backslash = map(3, 3),
Delete = map(3, 4), Copy = map(3, 5), PageDown = map(3, 6), Keypad7 = map(3, 7),
Keypad8 = map(3, 8), Keypad9 = map(3, 9), KeypadMinus = map(3, 10), LeftControl = map(3, 11),
A = map(3, 12), S = map(3, 13), D = map(3, 14), F = map(3, 15),
G = map(4, 0), H = map(4, 1), J = map(4, 2), K = map(4, 3),
L = map(4, 4), Semicolon = map(4, 5), Quote = map(4, 6), Return = map(4, 7),
Keypad4 = map(4, 8), Keypad5 = map(4, 9), Keypad6 = map(4, 10), KeypadPlus = map(4, 11),
LeftShift = map(4, 12), /* unused */ Z = map(4, 14), X = map(4, 15),
C = map(5, 0), V = map(5, 1), B = map(5, 2), N = map(5, 3),
M = map(5, 4), Comma = map(5, 5), FullStop = map(5, 6), ForwardSlash = map(5, 7),
RightShift = map(5, 8), Up = map(5, 9), Keypad1 = map(5, 10), Keypad2 = map(5, 11),
Keypad3 = map(5, 12), CapsLock = map(5, 13), LeftAlt = map(5, 14), Space = map(5, 15),
RightAlt = map(6, 0), RightControl = map(6, 1), Left = map(6, 2), Down = map(6, 3),
Right = map(6, 4), Keypad0 = map(6, 5), KeypadDecimalPoint = map(6, 6), KeypadEnter = map(6, 7),
Max = KeypadEnter,
};
};
// Resource for the keyboard protocol: https://github.com/tmk/tmk_keyboard/wiki/ACORN-ARCHIMEDES-Keyboard
struct Keyboard {
Keyboard(HalfDuplexSerial &serial) : serial_(serial), mouse_(*this) {}
void set_key_state(int row, int column, bool is_pressed) {
states_[row][column] = is_pressed;
void set_key_state(uint16_t key, bool is_pressed) {
states_[key] = is_pressed;
if(!scan_keyboard_) {
logger_.info().append("Ignored key event as key scanning disabled");
@ -28,10 +84,20 @@ struct Keyboard {
}
// Don't waste bandwidth on repeating facts.
if(posted_states_[row][column] == is_pressed) return;
if(posted_states_[key] == is_pressed) return;
// Post new key event.
enqueue_key_event(row, column, is_pressed);
enqueue_key_event(key, is_pressed);
consider_dequeue();
}
void set_mouse_button(uint8_t button, bool is_pressed) {
if(!scan_mouse_) {
return;
}
// Post new key event.
enqueue_key_event(7, button, is_pressed);
consider_dequeue();
}
@ -79,11 +145,17 @@ struct Keyboard {
enqueue(0, 0);
break;
case NACK: case SMAK: case MACK: case SACK:
case NACK: case SMAK: case MACK: case SACK: {
const bool was_scanning_keyboard = input & 1;
scan_keyboard_ = input & 1;
if(!scan_keyboard_) {
posted_states_.reset();
} else if(!was_scanning_keyboard) {
needs_state_check_ = true;
}
scan_mouse_ = input & 2;
logger_.info().append("ACK; keyboard:%d mouse:%d", scan_keyboard_, scan_mouse_);
break;
} break;
default:
if((input & 0b1111'0000) == 0b0100'0000) {
@ -142,10 +214,13 @@ struct Keyboard {
if(state_ == State::Idle) {
// If the key event queue is empty but keyboard scanning is enabled, check for
// any disparity between posted keys states and actuals.
for(int row = 0; row < 16 && event_queue_.empty(); row++) {
for(int column = 0; column < 16 && event_queue_.empty(); column++) {
if(posted_states_[row][column] != states_[row][column]) {
enqueue_key_event(row, column, states_[row][column]);
if(needs_state_check_) {
needs_state_check_ = false;
if(states_ != posted_states_) {
for(size_t key = 0; key < Key::Max; key++) {
if(states_[key] != posted_states_[key]) {
enqueue_key_event(static_cast<uint16_t>(key), states_[key]);
}
}
}
}
@ -177,8 +252,9 @@ private:
HalfDuplexSerial &serial_;
Log::Logger<Log::Source::Keyboard> logger_;
bool states_[16][16]{};
bool posted_states_[16][16]{};
std::bitset<Key::Max> states_;
std::bitset<Key::Max> posted_states_;
bool needs_state_check_ = false;
bool scan_keyboard_ = false;
bool scan_mouse_ = false;
@ -206,9 +282,12 @@ private:
event_queue_.erase(event_queue_.begin());
return true;
}
void enqueue_key_event(int row, int column, bool is_pressed) {
void enqueue_key_event(uint16_t key, bool is_pressed) {
posted_states_[key] = is_pressed;
enqueue_key_event(row(key), column(key), is_pressed);
}
void enqueue_key_event(uint8_t row, uint8_t column, bool is_pressed) {
logger_.info().append("Posting row %d, column %d is now %s", row, column, is_pressed ? "pressed" : "released");
posted_states_[row][column] = is_pressed;
const uint8_t prefix = is_pressed ? 0b1100'0000 : 0b1101'0000;
enqueue(static_cast<uint8_t>(prefix | row), static_cast<uint8_t>(prefix | column));
}
@ -227,7 +306,6 @@ private:
static constexpr uint8_t SMAK = 0b0011'0011; // Last data byte acknowledge, enabling scanning and mouse.
static constexpr uint8_t PRST = 0b0010'0001; // Does nothing.
struct Mouse: public Inputs::Mouse {
Mouse(Keyboard &keyboard): keyboard_(keyboard) {}
@ -241,7 +319,7 @@ private:
}
virtual void set_button_pressed(int index, bool is_pressed) override {
keyboard_.set_key_state(7, index, is_pressed);
keyboard_.set_mouse_button(static_cast<uint8_t>(index), is_pressed);
}
private:

View File

@ -9,60 +9,13 @@
#pragma once
#include "../../KeyboardMachine.hpp"
#include "Keyboard.hpp"
namespace Archimedes {
static constexpr uint16_t map(int row, int column) {
return static_cast<uint16_t>((row << 4) | column);
}
/// Named key codes that the machine wlll accept directly.
enum Key: uint16_t {
Escape = map(0, 0), F1 = map(0, 1), F2 = map(0, 2), F3 = map(0, 3),
F4 = map(0, 4), F5 = map(0, 5), F6 = map(0, 6), F7 = map(0, 7),
F8 = map(0, 8), F9 = map(0, 9), F10 = map(0, 10), F11 = map(0, 11),
F12 = map(0, 12), Print = map(0, 13), Scroll = map(0, 14), Break = map(0, 15),
Tilde = map(1, 0), k1 = map(1, 1), k2 = map(1, 2), k3 = map(1, 3),
k4 = map(1, 4), k5 = map(1, 5), k6 = map(1, 6), k7 = map(1, 7),
k8 = map(1, 8), k9 = map(1, 9), k0 = map(1, 10), Hyphen = map(1, 11),
Equals = map(1, 12), GBPound = map(1, 13), Backspace = map(1, 14), Insert = map(1, 15),
Home = map(2, 0), PageUp = map(2, 1), NumLock = map(2, 2), KeypadSlash = map(2, 3),
KeypadAsterisk = map(2, 4), KeypadHash = map(2, 5), Tab = map(2, 6), Q = map(2, 7),
W = map(2, 8), E = map(2, 9), R = map(2, 10), T = map(2, 11),
Y = map(2, 12), U = map(2, 13), I = map(2, 14), O = map(2, 15),
P = map(3, 0), OpenSquareBracket = map(3, 1), CloseSquareBracket = map(3, 2), Backslash = map(3, 3),
Delete = map(3, 4), Copy = map(3, 5), PageDown = map(3, 6), Keypad7 = map(3, 7),
Keypad8 = map(3, 8), Keypad9 = map(3, 9), KeypadMinus = map(3, 10), LeftControl = map(3, 11),
A = map(3, 12), S = map(3, 13), D = map(3, 14), F = map(3, 15),
G = map(4, 0), H = map(4, 1), J = map(4, 2), K = map(4, 3),
L = map(4, 4), Semicolon = map(4, 5), Quote = map(4, 6), Return = map(4, 7),
Keypad4 = map(4, 8), Keypad5 = map(4, 9), Keypad6 = map(4, 10), KeypadPlus = map(4, 11),
LeftShift = map(4, 12), /* unused */ Z = map(4, 14), X = map(4, 14),
C = map(5, 0), V = map(5, 1), B = map(5, 2), N = map(5, 3),
M = map(5, 4), Comma = map(5, 5), FullStop = map(5, 6), ForwardSlash = map(5, 7),
RightShift = map(5, 8), Up = map(5, 9), Keypad1 = map(5, 10), Keypad2 = map(5, 11),
Keypad3 = map(5, 12), CapsLock = map(5, 13), LeftAlt = map(5, 14), Space = map(5, 15),
RightAlt = map(6, 0), RightControl = map(6, 1), Left = map(6, 2), Down = map(6, 3),
Right = map(6, 4), Keypad0 = map(6, 5), KeypadDecimalPoint = map(6, 6), KeypadEnter = map(6, 7),
};
/// Converter from this emulator's custom definition of a generic keyboard to the machine-specific key set defined above.
class KeyboardMapper: public MachineTypes::MappedKeyboardMachine::KeyboardMapper {
public:
static constexpr int row(uint16_t key) {
return key >> 4;
}
static constexpr int column(uint16_t key) {
return key & 0xf;
}
// Adapted from the A500 Series Technical Reference Manual.
uint16_t mapped_key_for_key(Inputs::Keyboard::Key key) const override {
using k = Inputs::Keyboard::Key;