A TRS-80 Model III BASIC text editor

I bought my first computer about 40 years ago, a TRS-80 Model III from Radio Shack. It had 48Kb of RAM and a 2.03 MHz 8 bit CPU and cost about $2000, or about $5600 in today's dollars. For comparison, the computer I'm using now is five years old, has 16Gb of RAM (about 300,000 times that of my first computer), a quad core 2.6 GHz 64 bit CPU, and cost about $800.

TRS-80 Model 3 01

TRS-80 Model III, Wikimedia Commons

TRS-80 Model 3 01

TRS-80 Model III, Wikimedia Commons

TRS-80 Model 3 01

TRS-80 Model III, Wikimedia Commons

The TRS-80 had Tandy's version of the BASIC programming language built-in. As an engineering student I'd taken classes in Fortran and assembly language, but writing programs for my own computer was practically addictive. I eventually quit my job as a patent attorney and returned home to SC with a vague idea I could develop continuing legal education (CLE) classes in law office automation and make money teaching lawyers how to use computers.

I set about gathering intel on law office operations, working part time as a lawyer doing wills and divorces and real estate closings. I also enrolled in computer science classes and honed my presentation skills by teaching a class in BASIC, and even wrote my own program for printing legal forms. My TRS-80 is long gone, but I still remember how its hardware limitations affected the general design of the code for my "word processor" program.

When personal computers first came into use, they typically only ran one program at a time, so letting the processor remain idle while waiting for keyboard input was not a problem. Computers now use interrupts or direct memory access (DMA) for input and output operations. With interrupts, the input or output device sets an interrupt line when it is ready to send or receive data, and waits for the CPU to respond before proceeding. DMA allows the input or output device to bypass the CPU and write to or read from memory directly.

In vintage machines like the TRS-80, input was by means of a memory mapped keyboard. When a key was pressed, it changed the value seen by the CPU in a specific memory location. Thus, to recognize the user's keyboard input, the program that was running had to read data from the memory address associated with each key at the same time it was pressed. In other words, whenever a program was expecting keyboard input from the user, it had to use a loop to keep checking the keyboard memory until a key was pressed.

To be useful, my program had to display documents being created or edited, print them as needed, and save them as files to be used later. That is, it had to be able to send output to three devices-- the computer display, a printer, and a file. Though I don't remember all the details, my code for both file and printer output involved simply copying the screen display.

All versions of BASIC included commands for reading user input from the keyboard and displaying program output on the screen. While these commands were convenient for handling short text strings or numeric values processed by a program, they were not well suited for editing or displaying entire documents. What proved more useful were lower level functions available in the TRS-80 version of BASIC-- PEEK and POKE-- for reading and storing data at specified memory locations. I used the PEEK function in a loop to detect whether the user had pressed a key. If a key was pressed, POKE was called to display the corresponding character on the screen.

Keys were mapped to different memory locations, so several addresses had to be checked to determine which key had been pressed. Once they were identified, though, displaying the characters was fairly simple. The TRS-80 screen display, like the keyboard, was mapped to specific memory locations, but the mapping was not what you might expect to find in today's high resolution graphics devices. Rather than storing the brightness of each pixel, or even just a 1 or 0 to indicate whether it was on or off, each 8-bit unit of data in the display memory was mapped to an 8 by 12 pixel area on the screen. The character for the ASCII code in each memory location was displayed in the area to which it was mapped on the screen. The entire screen was 512 by 192 pixels, corresponding to a character matrix of 16 lines, each 64 characters wide. The display memory was contiguous, starting with the address corresponding to the top left character position on the screen and proceeding left to right, top to bottom.

In my program I used a "cursor" variable to hold a display memory address that kept track of where I was typing. Each time the program loop executed, if the PEEK function detected that a key had been pressed, the POKE function was called to store its value at the current address in the cursor variable. The cursor was then simply incremented, so the characters would be displayed on the screen in the order they were typed by the user.

To allow documents to be created and edited, several refinements to my main program loop were needed. Obviously, if the entire document would not fit on the screen, part of it would have to be moved to a different part of memory, and the freed-up display memory reset to blank space characters. Inserting text would require a way to navigate to an insertion point, e.g. by interpreting arrow keys differently than regular character keys, as well as some means, like displaying an otherwise unused character, to show where text would be inserted. While a block of memory was being moved to realign the screen or make room for text to be inserted, some keystrokes might be missed if I were to continue typing. While less than ideal, interruptions like these were tolerable since they were relatively infrequent.

A more significant issue involved words that broke across the end of a line. In that situation, the cursor address had to be moved forward enough for the entire word to fit on the new line. Then the first part of the broken word had to be copied to the new line and its original position filled with space characters. I modified the main program loop to spread these actions out over successive loop iterations, reducing the chance that any keystrokes would be missed.

By keeping track of the last address at which a space was typed, the starting and ending addresses of the characters that had to be moved to the next line could be readily determined. Since the display was 64 characters wide, the lowest 6 bits of the cursor address indicated its position on the line. If a space was typed at the beginning or the end of a line, indicating that the last word did not break, nothing needed to be moved to the new line. Otherwise, the cursor was moved forward, the character that had just been typed displayed in new cursor position, and "copy" and "blanking" flags were set.

In the loop iterations that followed, the program continued to check for and display new characters. It would also check the copy flag. If the copy flag was set, the broken portion of the word on the previous line would be copied, the copy flag cleared, and the program would continue with the next loop iteration. If the copy flag was not set, the blanking flag would be checked. If the blanking flag was set, the end of the previous line where the broken word was originally displayed would be filled with space characters, the blanking flag cleared, and the program would loop again. My scheme worked reasonably well. As the end of each line was reached, the sequence of changes to the broken word was discernible, but rarely were any characters dropped.

Of course, my handcrafted application was primitive by today's standards. Many present-day text editors like notepad++, atom or nano are freely obtainable and have far greater functionality than I even imagined possible. For perspective, however, consider that downloading software wasn't possible till well after the world wide web was invented in 1989. The DOS version of MS Word was available for IBM PC's in 1983, but Apple's Macintosh, the first personal computer with a graphical user interface (GUI), didn't come out till the mid 80's. Even the term "word processor" that we now think of as a software application for a general purpose computer was at that time still associated with a stand-alone dedicated device, essentially a glorified electronic typewriter. In any case, crude as it was, my little Tandy BASIC program saved me a lot of time preparing documents to be filed in court.

Postscript:
I never did develop CLE classes. It seemed there was too much I needed to learn about computers, so I decided to go to grad school.

Submitted 8/14/21, 11:27 PM