Dvorak on the Tandy 102

Here’s my journal of what I did to remap the keyboard on my Tandy 102 to be dvorak. These notes are raw and uneditted, so they might be hard to read, but you can see basically what I did. I added some pictures just to make it more interesting.

At the risk of pushing my opinion too much, I think for a long time the Tandy 102 was one of the few machines that just got it right for a laptop. It comes pre-loaded with a suite of useful tools; it powers on instantly (no waiting for standby or hibernate); it is entirely solid-state, so you can drop it and mash it and it won’t break; it has a comfortable full-sized keyboard; it is light; and the battery life is phenomenal, and when you run out, you can replenish yourself with just four AA batteries. And the thing has built into a modem, RS-232, and expansion ports. Up until a few years ago, few Windows laptops could claim even half of these features at ten times the price! The only problem I had with it, until now, is that it didn’t support the dvorak key mapping. Here’s how I fixed it.

Remove Boot ROM

Remove boot ROM. Rom is of through-hole type; need to recover nondestructively. Note that pins are crimped on the bottom, so heating the board will not release the chip; crimps must be individually undone. Use ChipQuik desoldering alloy to re-alloy the solder compounds.
Undo crimps one at a time using hot soldering iron tip to push pins back into a straight position.
Use “tongs” soldering iron to heat most of the pins at once and rely on thermal mass to keep ChipQuik alloyed pins liquid.
Remove chip; recondition pins, clean board with soldering braid. Attach new socket. Verify removed chip works by inserting chip into socket and booting system. Good, it works.

Read out ROM

Read out ROM contents using ROM reader. Need to reconstruct pinout to determine what ROM type to use. Based on the adjacent chip (6264LP SRAM chip) one can infer that this ROM may have a pinout similar to a 27C256. Attempt to read chip. Found that all zero’s are returned from reader. Query if pinout is valid. Buzz-out pins and verify that pinout is correct for 27C256. Query whether ROM has a lock-out based on the Vpp pin, or if the programmer is doing something screwy with Vpp that could be locking out the chip. Oscilloscope traces reveal nothing unusual. Check to see how Vdd is doing. Noticed that Vdd does not rise properly on ROM reader (EMP-30). Hypothesize that current limiting is employed in the ROM reader and this mask ROM consumes an unusually large amount of current. Consider connecting test clips from ROM to voltage source to force ROM power-up (risky, could damage programmer and/or ROM if this is not correct). To limit risk, try jumpering from Vpp over to Vdd, such that internal current limits of ROM reader are still in place. Noted that Vdd rises a little higher, and return data is garbled but looking more alive. Heck, I’m impulsive tonight so connect supply onto Vdd to force ROM into power-up. Risk pays off! A complete ROM image appears in the ROM reader buffer. And there you go:

Hardware Analysis: Keyboard

Note keyboard ribbon cable maps partly to 8155 directly as well as 40H367 (infer that 40H367 is a low power CMOS variant of the 74xxx series; web search turns up nil for datasheets and Toshiba website does not document this series anymore). 40H367 are buffer/line drivers. Infer these are used to drive keyboard scan matrix.

Pin 9 on the 8085 AH (RST5.5) is connected to PC3 (pin 1 on 8155) which is also functional as the Port B interrupt. Noted that PB0/1 seems to have some connection to the keyboard; suspect that keyboard event generates interrupt.

Interrupt handler for RST5.5 originates at 0x2C. Code at 02C contains a jump to location 0xF5F9. This appears to be in main memory; infer that memory map has ROM on bottom since boot vector is at 0 and ROM is only 32k. Main memory map has not been confirmed through measurements.

Hypothesize that interrupt handler is copied to main memory at some point in time. Try to localize code segment in ROM by either finding copy routine in initialization sequence or identify based on unique instructions that access 8155 register space. Choose latter path; its more fun.

Need to determine location of 8155 to find in/outs to its chip enable location.

Searching for location: CE pin of 8155 maps to pin 9 of 40H011 gate. This should be a triple-3-input AND gate. Pin 9 is an “A” input. Not the pin we are looking for; search more. Also maps to pin 12 of 40H138 3-8 decoder. Excellent, pin 12 is “Y3_N” output of decoder. We have found a drive point.

Theorize that 40H138 decoder is fed addresses from 8085. Search for connectivity there. Noted use of 40H367 buffers to amplify address drive of 8085. This will complicate search; must be done in at least 2 phases.

Refer to 8085 datasheet. Note that I/O ports are mapped only to top 8 bits, so I/O space is only 256 bytes large. Revise location opinion to location 0xBX.

Search for Keyboard Table Stub

Refer to disassembly of ROM. Search for instruction of type IN 0xBX. This is opcode 0xDB 0xBX. In particular, we are looking for stuff that tickles Port B of 8155, so refine search to 0xDB 0xB2 or 0xDB 0xBA.

Ida returns unidentified data segments with DB BA sequences. This is good. The fact that Ida did not encounter these during its initial walk through the code means that this was unreachable, which is consistent with a code block that is copied to memory and executed later on.

Found candidate function at 0x5359 in ROM space. Not sure where it gets copied into RAM yet. Makes a lot of calls to in/out on the 8155 on ports A and B, which are the keyboard ports.

Function is complicated and multi-tiered, still not obvious where mapping from key code to ASCII code happens.

That looks a heck of a lot like a keyboard mapping table to me. Tempted to modify and burn a ROM to test theory, but 27C256 parts aren’t in yet so I’ll keep on poking around at the code while I get progressively later for dinner :P

To confirm hypothesis, look for instruction motifs that could use 7BF1-ish area as a table lookup.
Not yielding any results.

Try searching from boot vector for any clues.

Noted that stack pointer is initialized to 0xFCC0. This supports ROM-low, RAM-high hypothesis. 831 bytes or so left for stack (assume it grows up???)

cool! F5F9 is the interrupt handler we were looking for. Let’s check it out.
ouch, the interrupt handler is just this:

ROM:0363 ei
ROM:0364 ret

Foiled! but not all is lost. Hypothesize that runt handler is installed while system initializes to prevent keyboard events from fouling up machine during initialization time. Thus, a secondary copy might exist somewhere. Query for other memory-copying routines.

One will observe that the numeric keypad mode does a mapping of m=0, j=1, k=2, etc. So we must be really close. This also indicates that possibly getting the numeric keypad mode to work correctly with dvorak mappings could be a bit of a pain because they special case that computation.

Also, reviewing the code segment some more, one can see that the “h” register is getting the location of the mapping table, and then a series of “dad” (direct add, basically index adds of “h”) instructions are called. Then, memory is fetched off of derefrences from [h]. I think it is pretty safe to say this is where the mapping occurs.

Testing

Now, to test the theory, let’s patch the location and burn some ROMs.

Let’s figure out what the new table mapping should be. Basically, I think this table works as follows:

Your website has some incredibly beneficial information on it. I find your approach helpful and stimulating. I question if your background is truly in security or writing. Just kidding. I truly do take pleasure in your material appreciate it.