Talking to the LCD panel from a TRS-80 Model 100 (aka Tandy M100) and clones

For my first not-tiny Arduino project, I set out to learn how to use this LCD panel from my junk box. It's out of one of the first true laptop computers, which came out in the early 80's and ran for 20 hours on 4 AAs.
The LCD has a resolution of 250x64 pixels, is graphical, reflective, unlit, and draws very little power.
It's not terribly useful as a general purpose device since it has a small viewing angle, but you may find this useful if you're testing one, or if you have a M100 with functional LCD but broken guts, and want to use it for something.

You can learn all of this by studying the service manual for the M100 and data sheet for the driver chips, HD44102 arranged in 2 rows of 5 chips. But since I've now done this, I thought I'd share.

Logic level is 5V, TTL- and CMOS-compatible.

The LCD is connected to the mainboard via a 30-pin cable. This is the pinout:
1: VDD. +5V to HD44102 and opamp. The opamp generates other voltages for the HD44102.
2: BZ. Buzzer. On my panel from an M100 clone (Olivetti M10) this was NC.
3: VEE. -5V to opamp. Not critical, I give it -4V from a Li-ion and it works fine. Draws about 2 mA.
4: V2 on HD44102. Contast adjustment for LCD, 0-4V. I used analogWrite and an RC low-pass filter. Without a filter the LCD will flicker a lot.
5: GND
6: GND
7: CS4. Chip select lines. 0 is top left, 0-5 is top half, 9 is bottom right, as seen on the LCD screen.
Each chip controls 50 columns, 32 rows. Whole screen has 250 columns, 64 rows.
8: CS3
9: CS9
10: CS2
11: CS8
12: CS1
13: CS7
14: CS0
15: CS6
16: CS5
17: Reset, active LOW. Reset doesn't actually clear screen RAM, it only turns the display off and sets the write mode left-to-right. To clear screen RAM, you need to fill it all with zeroes.
18: CS01: another chip select line for all chips. Active HIGH. If you have the LCD on a bus, use this for tri-state control of the data lines. I just connected it to +5V.
19: Clock. Write to LCD on falling edge. Read from LCD on HIGH.
20: Read/Write. HIGH: read data from LCD. LOW: write data to LCD.
21: Data/Instruction: HIGH: data on bus. LOW: instruction (write) or status (read) on bus.
22: D0: All data lines are bidirectional.
23: D1
24: D2
25: D3
26: D4
27: D5
28: D6
29: D7
30: NC

You can write to many chips at once, but you should only read from one at a time.
Every chip has 4 banks, each bank is a row 8 pixels (1 byte) high, 50 wide, addressed 0-49. Perfect for 5x7 fonts. The LSB of each byte is the top pixel.
When several bytes are written, they appear in adjacent columns. This can be set to go left-ro-right or right-to-left. It wraps automatically.
An instruction can be used to select a bank and column.
The banks can be arranged in sequences 0-1-2-3, 3-0-1-2, 2-3-0-1 or 1-2-3-0, enabling lower-latency vertical scrolling.
After a power loss, column is 0 but current bank and/or bank sequence (not sure which, or both) may be random.

Instructions:
0b00111001: display ON (LCD shows contents of display RAM).
0b00111000: display OFF (display RAM persists and can be written to/read from, but nothing is displayed).
0bBBAAAAAA: select bank BB (00-11), address AAAAAA (00-49 decimal, 0x00-0x31).
0bBB111110: set bank BB to be the top bank.
0b0011101D: set writing direction D: 0=right-to-left, 1=left-to-right.

Status flags, output by LCD when reading from it in instruction mode:
BDER0000: B=busy, D=writing direction, E: display enabled (on), R=reset active (1 if Reset pin os LOW). 0000=padding/irrelevant.

I made a function for reading the busy flag, but it was never active. I think all timings but one are impossible to beat by a 12 MHz Arduino. Since everything worked I haven't studied the timing charts any closer.

When reading data from the LCD, a dummy read must be done before the correct data will be output. Subsequent reads will read the next byte according to the read direction. The data is available as long as the clock line is HIGH.
I have not actually implemented this function yet, this is just what I've read.

M100 service manual: http://ftp.whtech.com/club100/doc/t102-service-manual.pdf
HD44102 data sheet: datasheet HD44102