Thursday, June 25, 2020

My quick and dirty 3174 control unit brings the 3178 terminal to life

WHY NOT JUST USE ANDREW KAY'S CONTROLLER

Andrew has done a brilliant job building a substantially complete 3174 controller for use with two terminal types, a 3483 and a 3279-2, both of which he owns. However, the 3178 has a different keyboard layout, therefore a majority of the keycaps will be misinterpreted by his existing code.

I am helping build a mapping for my keyboard to fit into his code, but it will be a bit of time before it is integrated and I have the entire oec package running. In the interim, I made use of his pycoax package of utility tools and built a python program to act as a simple 3174. 

WHY A CONTROLLER PROGRAM IS NEEDED

Almost all the functionality of the 3270 class terminals is implemented in the control unit (CU), such as the 3174. The terminal sends keystrokes back in response to polls from the CU but otherwise ignores the keypresses. 

The other, independent half of the terminal is a 2000 byte buffer, called the regen buffer, organized into 24 lines of 80 characters plus a special final line that is called the Operator Information Area but could casually be called the status line. The CU will write data into the regen buffer and those bytes select a character that is displayed on the screen. 

The operator is accustomed to pressing keys and seeing the character matching that keycap appear on the screen at the location where the cursor is positioned. Arrow keys allow movement of the cursor around the screen, and other control keys can effect the screen in different ways. However, the connection between keystroke and screen appearance is totally controlled by the CU.

BASICS OF MY CONTROLLER PROGRAM

I built a module that associates each scan code from the keyboard with its role. There are three types of scan codes that are returned to the CU - hardware events, control keys and characters that display on the screen. Control keys can be the arrow movements, TAB keys and many other types. 

The scan code for a given physical key is fixed, however the character or function associated with that key depends on two modifier conditions. The ALT key is held down to cause a given key to be interpreted as its ALT modified role. If the operator has shifted the keyboard to upper case, by use of keys like Up Shift or Caps Lock, then the scan code is interpreted as its shifted role. If the keyboard is not shifted up and the ALT key is not depressed, then the key is interpreted in its base role. 

My table for scan codes keeps track of several facts for each code. For keys that produce a displayable character, we store the regen buffer code to display the character in both the base role and the shifted role. We also store the ASCII character for base and shifted roles. For keys that produce a control function, we store the base and ALT function. A few codes represent hardware events such as Power On Reset Complete, but we can ignore these. 

My quick and dirty program loops sending POLL commands to the 3178. We receive back scan codes when a key or event has occurred. I look up the scan code and act appropriately.

If the code is a displayable character, I pick up the regen buffer code and write that character into the regen buffer. In that way, the pressed key shows up as a character on the screen. If the key is pressed while the keyboard is shifted up, I use the shifted version instead of the base version. For example, the keycap with J on it will pick up the code for a J if not shifted, but if the keyboard is shifted up, we pick up the code for 4 instead. The keycap shows J on the bottom and 4 on the top of the cap. 

I also keep track of the cursor position. The terminal maps the first 80 characters of the regen buffer to the bottom status line, then begins at position 81 with the top left position, line 1, column 1. Each time the user types a character that can be displayed, I write its code to the buffer and bump the cursor position up by 1. 

I then implement a number of the control keys, based on the key pressed and whether the ALT key is also depressed. The arrow keys increment or decrement the cursor position by 1 or 80, thus moving the cursor up, down, left or right. The HOME key moves the cursor to line 1 column 1. New Line moves the cursor to column 1 of the next line. A few others are implemented.

Many of the control keys just send a special code to the program but don't affect the displayed screen image or contents of the regen buffer. Program Function keys (PF1 to PF24), Program Action keys (PA1 to PA3), RESET, ENTER, and PRINT are examples. All I do when I receive one is print a message on my laptop screen 

NEXT STEPS

The current state of my program uses the terminal as a single unformatted display. This means that there are no attributes for individual fields, such as protected from user modification. It means that the field oriented functions such as TAB are not relevant. 

I enjoyed typing text, moving the cursor about and changing text on the screen. I watched the program recognize the various control keys. It was time to up my game, so that I could implement more functionality including field behavior. 

Over the next few days I will implement a shadow 2000 character buffer in the CU, writing displayable characters in both buffers. I will recognize and implement the function of attributes. These appear as blank positions on the screen, because the terminal doesn't display a character for any regen code in the range of xC0 to xFF. Those are the ranges of value that represent attributes. Ignored by the terminal in the regen buffer but important to the CU.

When a key is pressed, the CU must pay attention to the attribute that covers the current cursor location. If the field attribute is protected, the character is NOT placed into the buffers at that location. Instead, the status line shows an error status and all keypresses are ignored until the RESET key is pressed. 

The TAB function scans forward from the current cursor position until it finds the next unprotected attribute and sets the cursor one past that byte. Keys like INS and DEL control whether a pressed key replaces the data at the cursor location, is squeezed in moving the rest to the right, or the char is removed and the remainder pulled left; all of the movements are within the current field only. 

When the attributes are written, they have the M (modified) bit off. When a keypress causes a new character to be placed in the field, the CU will switch on the M bit. Generally the mainframe is only sent fields whose M bit is on, minimizing the data transferred over comm lines or a channel. 

2 comments:

  1. You’ve clearly explained the keyboard-to-controller relation, and how the controller manages the regen buffer. But what is the connection that lets the regen buffer appear on the screen? As I understand it, the buffer is in the controller? So how does the terminal know what pixels to write on the CRT? Is there a continuous stream of raster data going controller-to-terminal?

    ReplyDelete
    Replies
    1. Hi David

      I will do a quick post to clarify this as I didn't do a good job covering this in the post and many others may have the same question

      Delete