Authors
Publication
Pub Details
Date
Pages
BASIC Terms
What is bank switching?
The TS 2068 contains a thin black rectangular chip that is the “boss” — the Central Processing Unit (CPU). It is of the popular variety Z80A which has a long history of success. It runs just about everything but it takes orders from you.
The boss has a filing system in which there are 65,536 places to put things — every one at his “fingertips”. Each place has an address from 0 to 65,535. To help out all these places are “chunked” into eight file rooms. The rooms are called CHUNK 0 through CHUNK 7. Each contains 8192 places.
CHUNKs 0 and 1 normally contain information you can’t change. That is read-only-memory (ROM for short). What is normally in those two rooms is the HOME ROM. The other rooms are normally full of working files that can be changed, the HOME RAM (random-access-memory).
Business goes merrily on until you tell the boss to prepare a report on tape, which requires the services of EXROM.
“Where’s EXROM?” shouts the boss.
“Across town, boss.”
“Well, get it!”
“Yes, boss — er — where will I put him?”
“Hmmm — Kick HOME ROM out of CHUNK 0 and put EXROM there.”
“OK boss — suppose we need HOME ROM again?”
“Then we’ll get it back the same way, stupid.”
The job of taping the company report is completed and HOME ROM is moved back into CHUNK 0.
Now that is what is called bank-switching. Is it so hard to understand? You have a limited number of CHUNKs, but you can change what is in them.
The EXROM is one example. The DOCK where you put plug-in cartridges is another. All others are called expansion bank units (EXBUs).
You might think that anything connected to the computer is an EXBU. However, many things are just connected to the phone lines, so-to-speak…the input/output (I/O). A buss expansion unit, a BEU, is not always an EXBU. Confused? To be an EXBU it must be able to move into a chunk. The 2040 printer can’t even though it is a BEU. EXBUs require a special chip (or its equivalent) to communicate with the bank switching controller.
Remember that stupid helper? He was the one who did the actual bank switching. If he was told to switch out the chunk he works in, how would the boss ever get him back?
There are five choices:
- Don’t kick him out in the first place.
- Make sure the EXBU has his replacement.
- Use the telephone. (I/O)
- Talk to ROM.
- “Double talk” to memory.
Options a. and b. are bad; one mistake and all is lost. Option d. is bad because the chunk could have been RAM switched in.
That leaves options c. and e. The 2068 uses both, even though option c. would suffice. It is easy to understand using the I/O to contact the bank switching controller (BSC). It is not so easy to understand “double talk”, so we’ll explain that later.
This scenario might not have been needed by many of you, but a fresh viewpoint often causes a hand slap to the forehead. From here on we get very technical. Be forewarned.
Now that you know what bank switching is, and some of its problems — let’s review the I/O facilities of the 2068. “Review” is not really the right word because much of what is presented here is not in any better known book for the 2068.
To begin with, two I/O instructions will be explained — CLOSE and OPEN. The simpler of the two is CLOSE. In the process it will be necessary to explain other instructions as they are met. In this way, an orderly presentation is possible. Random wanderings are avoided.
Figure 1 shows a flow chart for the operation CLOSE. It has two main branches; one for HOME use, the other for EXBUs.
It should be mentioned here that TIMEX produced 2068s with the EXBU branch disabled because they had not yet marketed (nor did they ever market) EXBU devices. Through judicious use of error trapping, this branch can be healed. Lesser treatments permit adding the Mikrodrive, but why settle for less than complete capability?
This also resulted in unresolved “bugs” in the bank switching code which would have been fixed if tested with EXBUs. Many are as simple as a typographical error at 6610h in CALL_BANK, for which the cure is easy. The one at 0F48h in PASSIN is harder. Ideally the ROM should be replaced, but let’s be practical.
The syntax of the CLOSE statement is:
CLOSE # [streamname]
[streamname] is a numeric variable or a constant which has a rounded integer value from 0 through 15.
A mnemonic is preferred because it makes more sense and can be reassigned without rewriting program subroutines. The integer value will be called STRM# hereafter.
The first block in Figure 1 is CALL OFFSET. OFFSET uses STRM# to compute an index into a table of offsets called STRMS. It gets two bytes in Z80 reg BC and returns with reg HL pointing there.
The 38 byte STRMS table is located in the system variables area @ 23568. Initially the table contains:
The STRMS Table
| -3 | 23568 | 1 | 0 | KEYBOARD | LOWER SCREEN |
| -2 | 23570 | 6 | 0 | (ERROR) | MAIN SCREEN |
| -1 | 23572 | 11 | 0 | (ERROR) | RAM WRITE |
| 0 | 23574 | 1 | 0 | (KEYBOARD) | LOWER SCREEN |
| 1 | 23576 | 1 | 0 | INPUT COMMAND | LOWER SCREEN |
| 2 | 23578 | 6 | 0 | (ERROR) | PRINT/LIST |
| 3 | 23580 | 16 | 0 | (ERROR) | LPRINT/LLIST |
| 4 | 23582 | 0 | 0 | (User defined, initially closed.) | |
| .. | ….. | ” | ” | ” | |
| 15 | 23604 | ” | ” | ” | |
STRM#s -3, -2, and -1 are “hidden” from access by BASIC. All the others can be changed to suit your own purposes. The reason for hiding them is to insure the computer is not denied access to the keyboard, space for reports, or space for autolisting.
The normal use is not sacred, but you should rarely need to use more than the 12 available assignable streams from 4 to 15.
Channels are real data paths between one computer section and another. They might be temporary, permanent, near, or far — but they are real.
Streams are arbitrary labels applied to channels as a convenience. They are not real — any more than the printed word is the real sound as spoken. They are, however, very convenient.
Now comes an interesting piece of information. The offset is the lower 15 bits of reg BC. Bit 7 of reg B is a flag which indicates an EXBU is involved, when set.
For EXBU streams, the offset is an index into the system configuration table (SYSCON).
For HOME streams, the offset minus one is used as an index into the CHANS table:
The CHANS Table (Initially)
| CHAN# | ADDRESS | SUBADDR | VALUE | FUNCTION |
|---|---|---|---|---|
| 1 | 26688 | 26688 | 1280 | SENDTV (OUTPUT) |
| 26690 | 3086 | IN_K (INPUT) | ||
| 26692 | “K” | DEVICE SPEC. | ||
| 2 | 26693 | 26693 | 1280 | SENDTV (OUTPUT) |
| 26695 | 4543 | ERROR | ||
| 26697 | “S” | DEVICE SPEC. | ||
| 3 | 26698 | 26698 | 2791 | INSA (OUTPUT) |
| 26700 | 4543 | ERROR | ||
| 26702 | “R” | DEVICE SPEC. | ||
| 4 | 26703 | 26703 | 1280 | SENDTV (OUTPUT) |
| 26705 | 4543 | ERROR | ||
| 26707 | “P” | DEVICE SPEC. | ||
| ETB | 26708 | 26708 | 80h | End-of-table marker |
| 26709 | 00h | Bogey byte | ||
| … | 26710 | Start of BASIC area |
Notice that channels 2 and 4 differ only in the device spec. Even though SENDTV is listed for 3 of the 4 channels, its operation depends on flags defined by the device specifications.
Figure 1 — Flow Chart for CLOSE

One of the required functions of CLOSE is to reset any device dependent flags which could interfere with subsequent operation. An example of this is a table used to map the interrupt daisy chain for open devices.
That is why the CLOSE routine must look up the offset, read the device specifications, and execute any device dependent closing routines needed. Having done that it is time to rewrite the STRMS offset bytes.
The RSTSTR routine write 0’s for STRM# 4 through 15. Otherwise it looks up the default values in the SMINIT table. This is the same table which was used to initialize STRMS.
Whew! The job is done.
“NOT SO FAST THERE, BUSTER!” comes a cry from the 2068 as its screen goes crazy.
A problem exists. It seems like one of those mistakes that can ruin the end of an otherwise perfect day, but let’s keep cool.
It’s like this. After taking great pains to make sure that CLOSE can execute device dependent close routines if needed, the CL_TAB table is unable to point to any but one @ 5133 that does nothing at all — and then only if the device spec is K, S, or P. Attempting to CLOSE a different device results in chaos.
It is pointless to continue until this fine kettle of fish is dealt with. This one is a “stinker”. ON ERR GO TO doesn’t work because no error is detected!
SEARCH is called with the address of CL_TAB in reg HL and the device spec character in reg C. It looks at the first byte in the table. If it is 0, it signifies the end of the table. It can never be the first byte. If it matches the character in C, it returns with HL pointing to the following byte and condition code CY set. If it doesn’t match, it skips a byte and starts over again. Eventually it finds the end-of-table 0, providing a match has not been found first. It returns with HL pointing at the 0 and with condition code Z…but CL_TAB has no 0!
What happens when the device character is not found, is that the SEARCH routine keeps going; overrunning CL_TAB into OFFSET in search of a match or a 0. It sees an “8” @ 5143, an “0” @ 5153, and finally a “0” @ 5155. If our new device character is not “8”, or “0”, SEARCH will return with HL=5155 and condition Z set.
CLHOME fails to test the results of the search. It adds HL and the byte pointed to by HL. Then it jumps to that location. In case of K, S, and P, that location is 5133. No problem. The jump to 5155 is wild! It is in the middle of OFFSET, and also in the middle of an instruction.
Although the instructions are all wrong, nothing really damaging happens until the RET instruction is found @ 5161.
The intended return path @ 5133 POPs HL before RETurning. The wild branch doesn’t. As a result it “returns” to the address in HL (left on the stack), which points to the STRMS offset bytes. There is no machine code there, just offsets…EUREKA! Bright flashing lights! Suppose we sacrifice two STRM#’s so we can put in a real jump instruction to the emergency ward? Might work!
To save a long explanation, it does not work, with the limitations that STRM#s 11 and 12 are sacrificed and 13 to 15 used for EXBU.
POKE 23596,0 POKE 23597,195 POKE 23598, Least significant byte of patch routine address. POKE 23599, Most significant byte of same.
Of course, we have traded one problem for another, but isn’t it worth it? There are other patches needed to complete the fix, but we will wait until we meet them.
We were discussing CLOSE. Though HOME operations have been covered in detail, the EXBU branch has only been touched.
In the next installment, OPEN and the EXBU branches will come under scrutiny. We will also reveal the SECRET of why address lines A13 through A15 are the only ones buffered.
CL_TAB with Overrun
The bytes SEARCH steps through, from the start of CL_TAB into OFFSET. The third column is the byte immediately after each, which SEARCH would take as the offset.
| Address | Byte | Next | |
|---|---|---|---|
| 5127 | 75 | “K” | 5 |
| 5129 | 83 | “S” | 3 |
| 5131 | 80 | “P” | 1 |
| DDCL1 | “Do nothing routine” | ||
| 5133 | 225 | 201 | |
| OFFSET | |||
| 5135 | 205 | 30 | |
| 5137 | 31 | 50 | |
| 5139 | 203 | 92 | |
| 5141 | 254 | 16 | |
| 5143 | 56 | “8” | 4 |
| 5145 | 207 | 23 | |
| 5147 | 198 | 3 | |
| 5149 | 7 | 33 | |
| 5151 | 16 | 92 | |
| 5153 | 79 | “O” | 6 |
| 5155 | 0 | “End-of-table.” |
Assembler Listing
4970 SEARCH INC HL Skip offset byte
4971 LD A,(HL) Get byte
4972 AND A Set condition code
4973 RET Z Not found, end-of-table
4974 CP C Match?
4975 INC HL Point to offset
4976 JR NZ,-6 4970 No match, try next
4978 SCF Here if found\set CY
4979 RET Found
5023 CLOSE CALL OFFSET 5135 Returns HL->offset,BC
5026 LD A,B
5027 OR C
5028 RET Z Return if already closed
5029 CALL CLCHAN 5054
5032 RSTSTR LD BC,0 RESTORE STRMS entry as closed
5035 LD DE,41954
5038 EX DE,HL
5039 ADD HL,DE
5040 JR C,+9 5049 If STRM# > 3
5042 LD BC,4559 Here if STRM# = -3 thru +3
5045 ADD HL,BC
5046 LD C,(HL)
5047 INC HL
5048 LD B,(HL)
5049 EX DE,HL
5050 LD (HL),C
5051 INC HL
5052 LD (HL),B
5053 RET
5054 CLCHAN PUSH HL
5055 LD A,B Get flag byte
5056 CP 128 Is bit 7 set?
5058 JR NC,+22 5080 CLEXBU if set
5060 CLHOME LD HL,(CHANS) 23631 Here if HOME channel
5063 ADD HL,BC Compute target chan CHR$ addr
5064 INC HL
5065 INC HL
5066 INC HL
5067 LD C,(HL) Get device CHR$ from CHANS
5068 EX DE,HL
5069 LD HL,CL_TAB 5127
5072 CALL SEARCH 4971
5075 LD C,(HL) Get pointer offset
5076 LD B,0
5078 ADD HL,BC =5133 if found, 5155 if not
5079 JP (HL) Device dependent close routine
5080 CLEXBU SUB 128 Reset bit 7
5082 LD B,A
5083 LD HL,(SYSCON) 23740
5086 ADD HL,BC Compute addr of SYSCON group
5087 LD A,(HL) Get status byte
5088 CP 0
5090 RET Z Return if already closed
5091 CP 128
5093 RET Z Return if SYSCON end-of-table
5094 INC HL
5095 LD B,(HL) Get BANK#
5096 INC HL
5097 INC HL
5098 INC HL
5099 INC HL
5100 LD E,(HL)
5101 INC HL
5102 LD D,(HL) Get target addr CLSUBD
5103 LD H,D
5104 LD L,E
5105 LD A,(STRMNM) 23755 Get target STRM#
5108 LD E,A
5109 LD D,0
5111 PUSH DE Parameter=Target STRM#
5112 PUSH HL Target routine addr
5113 PUSH BC BANK#,MEMSEL (=xxxxx100)
5114 LD BC,3
5117 PUSH BC Parameter bytes passed
5118 LD BC,0
5121 PUSH BC Parameter bytes returned
5122 CALL CALL_BANK 26064 EXBU chan close routine
5125 POP HL
5126 RET to RSTSTR
; The SYSCON table status byte is set to 0 if it was open.
5127 CL_TAB 4Bh ="K"
5128 05h
5129 53h ="S"
5130 03h
5131 50h ="P"
5132 01h
5133 DDCL1 POP HL Here if permanent channel
5134 RET to RSTSTR
5135 OFFSET CALL FIX_U1 7966 Get STRM# from calc stack
5138 LD (STRMNM),A 23755 Save it
5141 CP 16 Max STRM#
5143 JR C,+4 5147
5145 RST 8
5146 17h Error O:Invalid stream
5147 ADD A,3 Add 3 to STRM#
5149 RLCA Multiply A by 2
5150 LD HL,STRMS 23568
5153 LD C,A
5154 LD B,0
5156 ADD HL,BC Compute addr in STRMS
5157 LD C,(HL) Get lsb of offset
5158 INC HL
5159 LD B,(HL) Get msb of offset and EXBU flag
5160 DEC HL
5161 RET Returns HL->offset,BC
5162 OPEN CP 44 =","\Implies MEMSEL follows
5164 JR Z,+7 5171
5166 CALL END? 6980
5169 JR +13 5182\Here if not END
5171 CALL INTPT? 10377
5174 JR NZ,+8 5182\If execute
5176 CALL SKIPIT 9577\Blockade prevents execute
5179 CALL END? 6980
5182 RST 40
5183 01h Calc:S,T->T,S
5184 38h Calc:Return control to CPU
5185 CALL OFFSET 5135\Returns offset in BC
5188 LD A,B
5189 OR C
5190 JR Z,+24 5214
5192 EX DE,HL
5193 LD HL,(CHANS) 23631
5196 ADD HL,BC Compute addr in CHANS
5197 INC HL
5198 INC HL
5199 INC HL
5200 LD A,(HL) Get "d"
5201 EX DE,HL
5202 CP 75 ="K"
5204 JR Z,+10 5214
5206 CP 83 ="S"
5208 JR Z,+6 5214
5210 CP 80 ="P"
5212 JR NZ,-67 5145\Error
5214 CALL OPCHAN 5221
5217 LD (HL),E
5218 INC HL
5219 LD (HL),D
5220 RET to BASIC