|
The Memotech MTX Series |
|
MTX PC Keyboard Interface
Propeller Logic
Description [Courtesy of Bill Brendling]
[Also available as Bill's Open Document format file]
The Propeller chip is a fast 32 bit micro-controller,
designed for hardware interfacing, with eight largely
independent cores, called "Cogs" in Propeller speak. It can be
programmed in assembler, a high level language designed
specifically for the chip called "Spin", or in a number of other
languages such as C. In designing software for the Propeller it
is typical for each cog to be dedicated to a specific task, such
as controlling a piece of hardware, and for the cogs to
cooperate to implement the entire functionality.
The keyboard interface uses a 6MHz crystal which is
multiplied internally by 16, to give a 96MHz clock. This is
slightly over-clocking (although fairly common), the Propeller
was originally designed for a 5MHz crystal, and 80MHz internal
clock. Each of the Propeller cogs can execute one assembler
instruction in typically 4 internal clocks. At 96MHz clock, this
gives the Propeller, when using all eight cores, the capability
of executing 192 instructions per microsecond. For the keyboard
interface, the cogs are used as follows:
Master Cog
The propeller always starts by executing code written in Spin
on the first cog. This may be a major part of the software, or
it may just be initialisation code. In this case it initialises
some addresses in memory and then starts a cog for sending
diagnostic messages to the programming interface. After
outputting an initial diagnostic signature message, the master
cog reads the position of the keyboard type jumper. What happens
next depends upon the type of keyboard selected.
PS/2 Keyboard
If a PS/2 keyboard is selected, five additional cogs are
started (giving seven used in total), running:
- PS/2 interface
- Key matrix mapping
- MTX interface (2 cogs)
- Key map reprogramming
The function of these cogs are described below.
For the PS/2 keyboard, it would be possible for the master
cog to stop at this point. However, for diagnostic purposes it
continues to run, and sends key events and remap diagnostics to
the diagnostics cog.
USB Keyboard
If a USB keyboard is selected, then six additional cogs are
started (using all eight of the Propeller cogs), running:
- USB driver (2 cogs)
- Key matrix mapping
- MTX interface (2 cogs)
- Key map reprogramming
The USB driver cogs only provide a low level interface to the
keyboard. Routines on the master cog use this interface to
enumerate and configure the keyboard. The master cog next
flashes the keyboard LEDs in sequence (this helps to
differentiate USB mode from PS/2 mode which flashes all three
LEDs simultaneously).
Having completed keyboard initialisation, the master cog
starts a loop, repeatedly polling the keyboard for key status.
Any change (a key pressed or released) causes a key event code
(7 bit USB key number, plus 8th bit to identify key press or
release) to be placed in a first-in, first-out (FIFO) buffer for
processing by the key matrix mapping cog. The key event code is
also sent to the diagnostic output cog.
The master cog loop also checks the state of the keyboard
lock bits (maintained by the mapping cog), and if these have
changed, uses the USB driver to update the keyboard LEDs.
PS/2 Keyboard Driver
Much of the code was borrowed from the
Propeller Object
Exchange. When a key is pressed or released on a PS/2
keyboard, the keyboard sends 1-3 bytes of serial data over clock
and data lines to the Propeller. The PS/2 driver cog receives
this data and turns it into a one byte event code, with 7 bits
identifying the key, and one bit to indicate key press or
release. The key codes used are the same as those for USB keys.
These event codes are queued in the key event FIFO.
This cog performs two other functions:
- On startup of the cog, it first sends a reset command to
the keyboard, so that it is in a known state. This causes
the three keyboard LEDs to flash simultaneously. The
auto-repeat rate on the PS/2 keyboard is then set to the
slowest possible. I would have turned auto-repeat off if
that was an option. Note, on the MTX the keys will still
auto-repeat, but that is functionality built into the MTX
ROM, not the PS/2 keyboard repeat.
- This cog also checks the state of the keyboard lock bits
(maintained by the mapping cog), and if these have changed,
updates the keyboard LEDs.
USB Driver
The USB driver came from the Parallax forums (http://forums.parallax.com/discussion/121321).
The original version was produced by Scanlime (https://scanlime.org/2010/04/its-alive-bit-banging-full-speed-usb-host-for-the-propeller/).
This version supported full speed (12MHz) USB devices only. This
version requires the Propeller to be clocked at 96MHz.
The code was subsequently modified by Saucy Solition (https://github.com/SaucySoliton/propeller-usb-host)
to also support low speed devices (1.5MHz), and to work with an
80MHz Propeller clock.
The version used for the keyboard interface has been modified
slightly from the latter source:
- Operation with a 96MHz clock has been re-instated
(with conditional compilation options).
- The restriction on which propeller pins can be used for
the USB interface has been relaxed, although in the end no
advantage was taken of this.
- A small amount of diagnostic code was cleaned up.
- Despite these modifications, the author cannot claim
anything like full understanding of the operation of this
code.
As mentioned earlier, this code provides a low level
interface, which in principle can support many types of USB
device. Details of the keyboard implementation were copied from
(http://forums.parallax.com/discussion/167592/propeller-ansi-vt-100-terminal-with-vga-and-usb-keyboard-support).
Without the efforts of the above referenced authors, who’s
work was shamelessly borrowed, USB support would not have been
possible.
Key Matrix Mapping Cog
This cog retrieves key events from the FIFO buffer, and
updates an in-memory model of the MTX keyboard accordingly. The
Propeller code implements eight different mappings between PC
keyboard keys and MTX keys, depending upon the state of the
shift keys, and scroll-lock and num-lock flags:
- For many keys (such as the letter keys), the translation
from PC to MTX key is the same for all eight mappings.
- For some keys (such as the “9” key) the shifted
character (open bracket for the “9” key) is on a different
key on the MTX keyboard (MTX key “8” for open bracket). So a
different translation is used depending upon whether or not
shift is down.
- A few symbols (such as equals) have different shift
states on the PC and MTX keyboards. Because of the way the
MTX scans the keyboard, it is not possible to modify the
shift state for individual key presses. Therefore, Andy Key
defined (originally for MEMU, see
here) alternate keys to press to produce these symbols.
By default the Propeller uses the same translations.
However, if scroll-lock is selected, most of these symbols
are translated to one of the three key matrix positions
which don’t have a key on the MTX keyboard. The enhanced ROM
in the MTX+ then translates these additional locations to
the correct symbols. It is possible to load additional
drivers on an unmodified MTX which will also translate these
additional locations.
- To maximise usability for games, Andy Key defined for
MEMU a mapping for the numeric keypad keys which preserved
physical layout. By default the Propeller follows this
mapping. However, this results in the shifted keys producing
digits other than those displayed on the PC keys. Turning on
the num-lock bit, changes the mapping so that shifted keypad
keys produces the digits as displayed. Because Andy’s
mapping uses the keypad num-lock key for the MTX “Page”/”7”
key, the PC “F12” key is used (by default) to toggle the num-lock
bit.
- Engaging both scroll-lock and num-lock combines the
effect of the two previously described mappings.
It is possible to change any of the mappings, either
permanently by changing the mapping tables in the Propeller ROM,
or temporarily by re-programming from the MTX as described
below.
The translated MTX key has to be remembered so that the
correct MTX key can be released on receiving the corresponding
key release event.
As well as mapping PC key events to the MTX keyboard matrix,
this cog also maps keys to toggle the scroll-lock and num-lock
bits, and to generate an MTX reset.
MTX Interface
The MTX Z80 writes the drive lines with one instruction, and
reads the sense lines with the very next instruction. With a
real keyboard the sense lines update instantly (or at least at
the speed of light). The Propeller is significantly faster than
the Z80 but updating the sense lines is still a challenge.
Earlier versions of the keyboard interface assumed that only one
drive line is active at any one time. This is always true for
the MTX ROM, but may not be true for all games that implement
their own keyboard decoding. The Propeller code used a binary
search to identify the active drive line. This enabled the
required keyboard row to be selected using only three tests.
Tony Brewer made a number of observations on
MEMORUM:
- That it was common, at least on the Spectrum to have
multiple sense lines active at the same time, to enable
rapid detection of a key press.
- By unrolling the loop it was possible to process
multiple sense lines more rapidly than I had appreciated.
- By outputting logic ones for the active keys, rather
than logic zeros, it was possible to use the Propeller
hardware to combine results from multiple cogs. The
Propeller needs output buffers anyway to go from 3.3v logic
to 5v logic, and these buffers can be inverting to turn the
active ones into active zeros that the MTX expects.
As a result of these comments, the MTX interface now uses two
cogs, one of which samples the lower four drive lines and
outputs the corresponding sense bits, the other cog sampling the
upper four drive lines.
Key Map Reprogramming Cog
As described in the section on the “Key Matrix Mapping Cog”,
the Propeller firmware has eight different key mappings built in
to provide different compromises for the differences between PC
and MTX key layouts. However others may have different
preferences, for example Martin wanted the unshifted keypad to
produce numbers. Therefore this cog provides the ability to
temporarily update the mappings from the MTX. To do this the MTX
has to first disable keyboard scanning, so that this is not
sending any bytes to the keyboard drive port. It also has to
ignore the values on the sense lines while reprogramming is in
progress.
To enable reprogramming, the MTX writes the following
four bytes to the scan line port (port 0x05): 0xF0, 0x0F, 0x55,
0xAA. Once enabled, any byte sent to the scan line port with
less than two zero bits will disable reprogramming. Typically
0xFF will be used to complete the programming sequence.
Once programming is enabled, a sequence of four bytes is used
to update a map position:
Byte |
Bit
Pattern |
Meaning |
1 |
0101dddd |
dddd = 0 – 7: MTX drive line
number F: Dead key
E: Lock key D: Reset
key |
2 |
0100ssss |
For an MTX key:
ssss = 0 – 9: MTX sense line number For a dead
key: ssss = F (by convention,
although actual value is ignored) For a lock key:
ssss = 1: Num lock
ssss = 4:
Scroll lock For a reset key:
ssss = 1: Left reset
ssss = 2: Right reset
ssss = 3: Combined reset (single key will
reset MTX) |
3 |
001nktxx |
n = 0: Mapping
with num-lock off 1: Mapping
with num-lock on k = 0: Mapping with
scroll-lock off 1: Mapping
with scroll lock on t = 0: Mapping
with shift key up 1: Mapping
with shift key down xx = Top two bits of PC key
code |
4 |
00oxxxx |
xxxxx = Bottom five
bits of PC key code This byte also writes the new
value to the appropriate keyboard mapping table. |
If updating multiple mappings, the first three bytes only
have to be resent if they have changed from the previous value,
This means that the amount of data to be sent can be reduced by:
- Updating multiple keys with the same drive line
- Updating multiple keys with the same sense line
- Updating keys in the same map, and the adjacent PC key
codes (same top two bits)
The following table lists the key event codes used in the
Propeller, and are needed for bytes 3 and 4 of the key map
reprogramming. These are standard USB key codes, except for 0x64
to 0x6b which have been added to define the various shift keys.
Code |
Key |
Code |
Key |
0x04 |
Keyboard a and A |
0x38 |
Keyboard / and ? |
0x05 |
Keyboard b and B |
0x39 |
Keyboard Caps Lock |
0x06 |
Keyboard c and C |
0x3a |
Keyboard F1 |
0x07 |
Keyboard d and D |
0x3b |
Keyboard F2 |
0x08 |
Keyboard e and E |
0x3c |
Keyboard F3 |
0x09 |
Keyboard f and F |
0x3d |
Keyboard F4 |
0x0a |
Keyboard g and G |
0x3e |
Keyboard F5 |
0x0b |
Keyboard h and H |
0x3f |
Keyboard F6 |
0x0c |
Keyboard i and I |
0x40 |
Keyboard F7 |
0x0d |
Keyboard j and J |
0x41 |
Keyboard F8 |
0x0e |
Keyboard k and K |
0x42 |
Keyboard F9 |
0x0f |
Keyboard l and L |
0x43 |
Keyboard F10 |
0x10 |
Keyboard m and M |
0x44 |
Keyboard F11 |
0x11 |
Keyboard n and N |
0x45 |
Keyboard F12 |
0x12 |
Keyboard o and O |
0x46 |
Keyboard Print Screen |
0x13 |
Keyboard p and P |
0x47 |
Keyboard Scroll Lock |
0x14 |
Keyboard q and Q |
0x48 |
Keyboard Pause |
0x15 |
Keyboard r and R |
0x49 |
Keyboard Insert |
0x16 |
Keyboard s
and S |
0x4a |
Keyboard
Home |
0x17 |
Keyboard t and T |
0x4b |
Keyboard Page Up |
0x18 |
Keyboard u and U |
0x4c |
Keyboard Delete Forward |
0x19 |
Keyboard v and V |
0x4d |
Keyboard End |
0x1a |
Keyboard w and W |
0x4e |
Keyboard Page Down |
0x1b |
Keyboard x and X |
0x4f |
Keyboard Right Arrow |
0x1c |
Keyboard y and Y |
0x50 |
Keyboard Left Arrow |
0x1d |
Keyboard z and Z |
0x51 |
Keyboard Down Arrow |
0x1e |
Keyboard 1 and ! |
0x52 |
Keyboard Up Arrow |
0x1f |
Keyboard 2 and " |
0x53 |
Keyboard Num Lock and Clear |
0x20 |
Keyboard 3 and £ |
0x54 |
Keypad / |
0x21 |
Keyboard 4 and $ |
0x55 |
Keypad * |
0x22 |
Keyboard 5 and % |
0x56 |
Keypad - |
0x23 |
Keyboard 6 and ^ |
0x57 |
Keypad + |
0x24 |
Keyboard 7 and & |
0x58 |
Keypad Enter |
0x25 |
Keyboard 8 and * |
0x59 |
Keypad 1 and End |
0x26 |
Keyboard 9 and ( |
0x5a |
Keypad 2 and Down Arrow |
0x27 |
Keyboard 0 and ) |
0x5b |
Keypad 3 and Page Down |
0x28 |
Keyboard Return (Enter) |
0x5c |
Keypad 4 and Left Arrow |
0x29 |
Keyboard Escape |
0x5d |
Keypad 5 |
0x2a |
Keyboard Delete (Backspace) |
0x5e |
Keypad 6 and Right Arrow |
0x2b |
Keyboard Tab |
0x5f |
Keypad 7 and Home |
0x2c |
Keyboard Spacebar |
0x60 |
Keypad 8 and Up Arrow |
0x2d |
Keyboard - and _ |
0x61 |
Keypad 9 and Page Up |
0x2e |
Keyboard = and + |
0x62 |
Keypad 0 and Insert |
0x2f |
Keyboard [ and { |
0x63 |
Keypad . and Delete |
0x30 |
Keyboard ] and } |
0x64 |
Left Control |
0x31 |
Keyboard \ and | |
0x65 |
Left Shift |
0x32 |
Keyboard # and ~ |
0x66 |
Left Alt |
0x33 |
Keyboard ; and : |
0x67 |
Left Meta |
0x34 |
Keyboard ' and " |
0x68 |
Right Control |
0x35 |
Keyboard ` and ~ |
0x69 |
Right Shift |
0x36 |
Keyboard , and < |
0x6a |
Right Alt |
0x37 |
Keyboard . and > |
0x6b |
Right Meta |
Diagnostic Cog
This cog outputs diagnostic messages in serial format at
115,200 baud, 8 bits, no parity, 1 stop bit. The output is 3.3v
TTL on pin 39 (I/O bit 30) of the propeller, which is connected
to the programming connector.
The output consists of:
- Firmware identification string, including version
number.
- Keyboard type message (USB or PS/2).
- Cog initiation messages.
- USB configuration messages (if appropriate)
- Two digit key event codes, as per table above, with high
bit set for key release.
- Eight digit diagnostic codes from the remap cog.
This cog a standard Parallax Propeller object, accessed from
driver routines running on the main code. It is also capable of
receiving incoming serial characters from the programming
connector, although this feature is not currently used.
Firmware Distribution
Any upgrades to the Propeller application program will be
available below. If there are any updates to the hardware, a new
PCB will probably be required, firmware updates will likely be
specific to the hardware version that they are designed to run
on.
The Source file archive contains the
Parallax Spin language source code, the source files must be
compiled into a binary file that is loaded from the EEPROM when
the Propeller is powered on or reset. The
Propeller Tool includes software for programming in Spin and
Assembly but the easiest method of compiling the source files
for the MTX PCB application is to use the Open Source compiler,
OpenSpin.
It is a command line tool, with pre-built binaries for Windows,
Linux and Raspberry PI available from
Github.
Parallax
Propeller |
Version |
By |
Zip |
PCB |
Description |
|
|
|
|
|
180610 |
WB |
|
1.0 |
Modified key mapping, added
dynamic remapping |
180504 |
WB |
|
1.0 |
Optimisation of drive line
decoding (suggested by Tony Brewer) (Chips U3 & U4
must be inverting buffers, e.g., 7406, 7416) (All
future release will be written for inverting buffers) |
180429 |
WB |
|
1.0 |
Initial release supporting USB
and PS/2 keyboards (Chips U3 & U4 must be
non-inverting buffers, e.g. 7407, 7417) |
|
|
|
|
|
|
|
|
|
|
MTX "BASIC" ROM (ROM 'B')
(Optional) |
1.0 |
MA |
|
1.0 |
Enables "Scroll Lock" mode
without CP/M or SDX |
|
|
|
|
|
Software
The optional programs below allow MTX users with disk based systems to utilise the "Scroll Lock" mode without needing to modify the MTX
ROMs.
Ver. |
Host |
Zip |
PCB |
Description |
1.0 |
CP/M |
|
1.0 |
Initial release - enables
"Scroll Lock" for CP/M (.com) |
1.0 |
SDX |
|
1.0 |
Initial release - enables
"Scroll Lock" for non-CP/M SDX (.run) |
1.0 |
Tape |
|
1.0 |
Initial release - enables
"Scroll Lock" for "tape" users CP/M (.wav)
(Currently not tested on real hardware) |
|
|
|
|
|
|