1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
/*
Copyright (C) 2020-2022 Rafal Michalski
This file is part of SPECTRUSTY, a Rust library for building emulators.
For the full copyright notice, see the lib.rs file.
*/
//! Emulator components of various ZX Spectrum peripheral devices.
//!
//! ZX Spectrum keyboard emulation interface.
//!
//! Please see also [this](http://rk.nvg.ntnu.no/sinclair/computers/zxspectrum/spec48versions.htm#issue1)
use bitflags::bitflags;
#[cfg(feature = "peripherals")]
pub use spectrusty_peripherals::*;
bitflags! {
/// Every key's state is encoded as a single bit on this 40-bit flag type.
/// * Bit = 1 a key is being pressed.
/// * Bit = 0 a key is not being pressed.
#[derive(Default)]
pub struct ZXKeyboardMap: u64 {
const V = 0x00_0000_0001;
const G = 0x00_0000_0002;
const T = 0x00_0000_0004;
const N5 = 0x00_0000_0008;
const N6 = 0x00_0000_0010;
const Y = 0x00_0000_0020;
const H = 0x00_0000_0040;
const B = 0x00_0000_0080;
const C = 0x00_0000_0100;
const F = 0x00_0000_0200;
const R = 0x00_0000_0400;
const N4 = 0x00_0000_0800;
const N7 = 0x00_0000_1000;
const U = 0x00_0000_2000;
const J = 0x00_0000_4000;
const N = 0x00_0000_8000;
const X = 0x00_0001_0000;
const D = 0x00_0002_0000;
const E = 0x00_0004_0000;
const N3 = 0x00_0008_0000;
const N8 = 0x00_0010_0000;
const I = 0x00_0020_0000;
const K = 0x00_0040_0000;
const M = 0x00_0080_0000;
const Z = 0x00_0100_0000;
const S = 0x00_0200_0000;
const W = 0x00_0400_0000;
const N2 = 0x00_0800_0000;
const N9 = 0x00_1000_0000;
const O = 0x00_2000_0000;
const L = 0x00_4000_0000;
const SS = 0x00_8000_0000;
const CS = 0x01_0000_0000;
const A = 0x02_0000_0000;
const Q = 0x04_0000_0000;
const N1 = 0x08_0000_0000;
const N0 = 0x10_0000_0000;
const P = 0x20_0000_0000;
const EN = 0x40_0000_0000;
const BR = 0x80_0000_0000;
}
}
/// An interface for providing changes of a **ZX Spectrum** keyboard state to one of the `ULA` chipset emulators.
///
/// This trait is implemented by [ControlUnit][spectrusty_core::chip::ControlUnit] implementations which provide
/// a Spectrum's keyboard interface.
pub trait KeyboardInterface {
/// Reads the current state of the keyboard.
fn get_key_state(&self) -> ZXKeyboardMap;
/// Sets the state of the keyboard.
fn set_key_state(&mut self, keymap: ZXKeyboardMap);
}
impl ZXKeyboardMap {
/// Reads the state of 4 key lines from `ZXKeyboardMap` suitable for **ZX Spectrum** internal I/O.
///
///
/// ```text
/// line b 7f bf df ef f7 fb fd fe
/// [4] B H Y 6 5 T G V
/// [3] N J U 7 4 R F C
/// [2] M K I 8 3 E D X
/// [1] SS L O 9 2 W S Z
/// [0] BR EN P 0 1 Q A CS
///
/// [BR] BREAK/SPACE [EN] ENTER [CS] CAPS SHIFT [SS] SYMBOL SHIFT
///
/// key bits key bits
/// line b4, b3, b2, b1, b0 line b4, b3, b2, b1, b0
/// 0xf7 [5], [4], [3], [2], [1] 0xef [6], [7], [8], [9], [0]
/// 0xfb [T], [R], [E], [W], [Q] 0xdf [Y], [U], [I], [O], [P]
/// 0xfd [G], [F], [D], [S], [A] 0xbf [H], [J], [K], [L], [EN]
/// 0xfe [V], [C], [X], [Z], [CS] 0x7f [B], [N], [M], [SS], [BR]
/// ```
pub fn read_keyboard(self, line: u8) -> u8 {
let mask = !line;
let mut res: u8 = !0;
if mask == 0 {
return res;
}
let mut keymap = self.bits();
for _ in 0..5 {
res = res.rotate_left(1);
let key = keymap as u8;
if key & mask != 0 {
res &= !1; // pressed
}
keymap >>= 8;
}
// eprintln!("keyscan: {:02x} line: {:02x}", res, line);
res
}
/// Changes the pressed state of the key indicated as a key index.
pub fn change_key_state(self, key: u8, pressed: bool) -> Self {
let mask = ZXKeyboardMap::from_bits_truncate(1 << key);
if pressed {
self | mask
}
else {
self &!mask
}
}
}