mirror of
https://github.com/TomHarte/CLK.git
synced 2025-04-08 08:43:42 +00:00
Eliminate comparison costs.
This commit is contained in:
parent
26375dc023
commit
3be5d60b1e
@ -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.
|
||||
|
@ -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) {}
|
||||
|
@ -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.
|
||||
|
@ -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:
|
||||
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user