Wednesday, September 26, 2007

Symbolics Rev. C Keyboard Secrets

The ADB adapter has fulfilled its main purpose: providing an example of hardware which can speak to my Rev. C Symbolics keyboard.

The apparent trick is that the clock pulses must be narrow, without being too rapid (i.e., a relatively low duty cycle.) A 10 microsecond long low pulse on /CLR, followed 30 microseconds after the beginning of that pulse by the clock going low for roughly 9 microseconds, continuing with a clock period of approximately 50 microseconds does the trick. The ADB adapter pauses somewhat between groups of 11 clock pulses, corresponding to the natural "section breaks" of the keyboard mapping; I don't know if that is strictly necessary. My first crude approximation, using bit-bashing for the PIC with timing loops resulted in Caps Lock and Mode Lock that felt a bit sluggish---needing to be held down relatively long to "lock" or "unlock." The overall cycle time may be important in that regard.

In any event, I reconstructed the keyboard mapping from the LMKBD project, although I chose to count pulses from zero, rather than n=1 in that listing.

Unfortunately, this seems to make the PIC EUSART not fit the application: its clock pulses have a symmetric duty cycle. I had hoped to use the serial port intelligence to offload enough of the bit-handling to allow for rapid response that the ADB protocol seems to require. Perhaps I need to look at some of the other peripherals; can I use some pulse-width modulation output to drive the keyboard and the EUSART in synchronous slave mode together?

Tuesday, September 25, 2007

Baker's COMFY for the PIC?

I encountered Henry G. Baker's COMFY compiler a couple years ago. (Baker's site contains a text article, a TeX format article, and an Emacs Lisp implementation. The ACM published the two articles COMFY theory and COMFY-65) COMFY is not a very high-level language, in the conventional sense, but is an attempt to provide a clean but simple set of control structures on top of conventional machine code. Baker calls it 'medium-level.'

The resulting compiler is very small; its main task in life is to automate the generation of branch instructions, which is one of the tedious parts of tightly optimizing assembly programs. Yet it allows as well for arbitrary Lisp-style macros.

I found the concept intriguing, but I found the article and the compiler code itself rather obscure. Part of the obscurity is the unconventional names for the 6502 operations, unconventional notation for the addressing modes, and decimal numbers for opcodes (because Emacs Lisp does not accept other radixes). Another is that the implementation is lean-and-mean, emitting code bytes directly into a destination vector---the only output to look at is a vector filled with decimal numbers. The manipulations on the 6502 opcodes take advantage of the low-level bit patterns without explanation. Finally, it uses the term 'continuation', which, no matter how many times I think I understand it, scares me, probably because it introduces a highly abstract term into an area like assembly programming which is relentlessly concrete.

I've been learning about it by going through the code, restructuring a bit as I go. I'm beginning to be impressed by the subtlety of the code. One thing that is just dawning on me is that the return values of the code-emitting functions is as important as the side-effect. (To those of you chuckling, you see how far I have yet to go.) Lisp can hide that from you when it "looks imperative."

My longer term goal is to see if the same technique can be fruitful even within the more restrictive limits of the PIC. In order to get there, I'm going to have to gain confidence that I understand the formal concept of the 'win' and 'lose' continuations, which means, I think, having to come up with legible examples that compile to 6502 code, and use that to firm up my understanding of the compiler. Finally, I'll try to code the 'genbrc' routine for PIC branches.

For the "legible examples" part, I think I will try to break the lean-and-mean single-pass direct-to-binary compiler into a "compile to a vector or list with symbolic 6502 mnemonics" followed by a very simple 6502 assembly pass. A similar enhancement might accumulate a relocation table to allow more flexible linking. (I'm still not used to the idea that the code is emitted starting in high memory and working down.) I've begun abstracting out the addressing mode bit manipulations, and probably will add error-checking to make sure invalid opcodes are not generated by mistake.

One thing that I think that will have to go in the PIC version is the shallow binding mentioned in the TeX column, but not in the text version; without a stack, I'm not sure where to save anything. I'm also just a bit worried that the PIC has so many idiosyncracies (e.g., register pages controlled by special flags, instead of a uniform zero-page) that even a medium-level language doesn't help much.

(I should mention in passing Frode Vatvedt Fjeld's nifty little Lisp code to generate PIC instructions from the bit chart.)

[UPDATE: I should also mention a COMFY-based assember for x86, implemented in Scheme, called `Sassy', although I have never tried to use it.]

Monday, September 24, 2007

ADB adapter on its way...

David K. Schmidt evidently scrounged up another ADB converter box which he just sold to me. Assuming I haven't blown up my Symbolics keyboard, I may finally have what I wanted: a piece of hardware that knows how to talk to my Rev. C keyboard! I hope that will shorten the time to coerce my PIC circuit to do the same.

Tuesday, September 18, 2007

Beginner PIC mistakes, and detective work

Step 1 in the Symbolics keyboard to PIC project was not as quick as I had hoped.

It was pretty easy to generate the reset pulse, and get the serial port to send a clock signal to the keyboard. I then was using an oscilloscope to look at the keyboard response, but various attempts to get the PIC code to light up LEDs in response didn't work at all. In fact, I was being bitten by two bugs, which I used the PICkit 2 in-circuit debug to discover.

  1. An array overrun bug (it seems the default radix in MPASM is hex, so reading 16 bytes into a sixteen element array doesn't work! Unfortunately, my byte counter was located after the array, was stomped directly from 6 to zero, missing the "decrement and skip if zero" termination test until the array covered well into register bank 1.) Safety tip of the day: put your counter before the array!

  2. Something not addressed in the early lessons: ANSEL. The RX/DT pin of the 16F690 is shared with AN11, and the low bits of PORT C driving the LEDs are shared with AN4 through AN7. That means, unless one clears the corresponding bit in the ANSEL registers, they read as digital 0, no matter what the RX data is, and no matter what the state of my PORT C output. Toggling RC5 with a read-modify-write operation was clearing my LEDs before I could see them. Read your data sheets carefully!

A few tips/gripes on the PICkit 2 in-circuit debugging experience

  1. At least for newbies like me, and probably for more complex applications, any ICD is a great puzzle solver. At US$45 plus shipping, it is a great deal.

  2. The white triangle on the PICkit 2 programmer goes to pin 6 (near the "ICSP" silkscreen) of the AC164110---mark a triangle there to make it more foolproof.

  3. The green execution arrow stops after the line marked with the red B. I.e., the instruction with the breakpoint on it gets executed before control comes back to the user. This is counter to my habits built up using the similar looking VBA debugger in Excel.

  4. With the 16F690, you get only one active ICD breakpoint. That's much better than zero, of course.

  5. The W register indicator in the MPLAB IDE seems not to work (stuck at zero); look at the Special Function Register window instead.

  6. Another MPLAB IDE gripe: hovering over constants in code (such as a bit number) shows the value of the File Register at that constant address. Not so helpful when I want to check which bit position I am trying to flip.

  7. Modifying special function registers in the File Register window is evidently forbidden; modify them in the Special Function Register window.

Modifying special function registers directly is a real time-saver. Instead of downloading different code to set up the baud rate registers, I edit them by hand to experiment. (And, unfortunately, my Rev. C keyboard behaves differently at different clock rates! More to come on a separate page.)

Wednesday, September 5, 2007

Symbolics keyboard to PIC, step 1

The first step is to connect the Symbolics keyboard to the PIC. I am using the 16F690 which comes with the PICkit 2 starter kit on the low pin count demo board (Microchip DM164120-1). The keyboard cable mates to a 6-pin modular jack (such as Digikey part number 609-1061-ND), which I tacked onto the side of the board. Unfortunately, this mod jack has pin spacings of 50 mil "horizontally" between successive pins, so I bent up the odd pins and soldered the even pins to the demo board.

Mod jack pinKeyboard functionPIC functionPIC pin marking
5GND (N/C)
3Key DataRX/DTRB5

My first task will be to power up the keyboard, code a scanning loop, and try to detect keystrokes for a single key, such as the Left Control Key, displaying the count of key-down events in binary to the LEDs connected to RC0-RC3. If the keyboard is not debounced by the internal microcontroller, the count will not increment cleanly, but I hope to at least prove that I can talk to the keyboard and make sense of what comes back. I'm not sure how much current the keyboard will need, so I might have to power the demo board with an external supply.

[UPDATE: It turns out the standard numbering of modular jack pins is the reverse of the pin numbering of the P1 header inside the keyboard. I've corrected the table above to reflect the standard modular jack scheme. Looking into the opening of the jack, with the locking tab down, pin 1 is on the left side.]