Description
Programs
EPROM Programmer
Compact Flash Drive Utility
Mini Memory Module Line-By-Line Assembler Bug
Cartridge Bank Switching
The Texas Instruments TI-99/4A was an early home computer, released in June of 1981. The computer holds the distinction of being the first 16-bit personal computer, having a 16-bit TMS 9900 CPU running at 3.0 MHz.
![]() |
For a full description of the system, see this comprehensive Wikipedia entry. | ![]() |
| Disk: Miscellaneous.zip (V9T9 format) | |
| Programs with names in black are written/generated by me. Programs with names in red are copied from other sources. | |
| CATALOG | BASIC disk catalogue program from TI disk drive manual. |
| CFMGR CFMGS |
Compact Flash Drive Volume Manager. E/A 5 format. |
| CONV_BASES | Subroutine (for MERGE-ing into other programs) to convert a binary, decimal or hexadecimal number to binary, decimal or hexadecimal. Lines numbered from 10000. |
| DISASSMBLR | TMS 9900 assembly language disassembler, running under TI Extended Basic with 32K RAM. |
| DISASS/S DISASS/O |
Source and object files for assembly language utility to print to the screen in text mode (40 characters × 24 lines). |
| MGR3 MGR4 |
DM-1000 (V3.5) Disk Manager (copied from Funnelweb). E/A 5 format. |
| CART_RAM/S CART_RAM/O |
Source and object files for assembly language program to save/load the contents of the SuperCart RAM (>6000 - >7FFF) or MiniMem RAM (>7000 - >7FFF) to/from a data file. Also has an option to fill the RAM with zeroes. Load using E/A option 3 or MiniMem option 3, 1. Program auto-starts on loading and detects the cartridge type. Requires 32K RAM expansion to be present. |
| SC_START | Data file containing the RAM image for the SuperCart startup menu. |
| MM_LBLA | Data file containing the RAM image for the MiniMem Line-By-Line Assembler. Program names: OLD, NEW. |
| MM_LINES | Data file containing the RAM image for the MiniMem Lines demonstration program. Program name: LINES. |
| RD_REF_TBL | BASIC program to display the contents of the REF/DEF table when running with the Extended Basic, Editor/Assembler or MiniMem modules. |
| SYSTEX | XB/assembly language hybridisation program. Version 1.0, ©1985, Barry Boone. Allows you to save assembly language programs/utilities as part of XB program files. |
| XBOPT5 | E/A 5 format loader for Extended Basic. Version 3.1, 1987, Barry Boone. To use, make a copy of the program, then edit line 110 to specify the program to load. |
| Disk: The_Valley.zip (V9T9 format) | |
| RUN | An adventure game, published as a program listing in Computing Today magazine, April 1982. Choose your character type carefully ... Barbarians recover quickly but their magic doesn't come easily. A Wizard? Slow on the draw and slow to mature ... but live long enough and grow wise enough and your lightning bolts are almost unstoppable ... The Valley is a real-time game of adventure and survival. You may choose one of five character types to be your personal 'extension of self' to battle and pit your wits against a number of monsters. Find treasure, fight a Thunder-Lizard in the arid deserts of the Valley, conquer a Kraken in the lakes surrounding the dread Temples of Y'Nagioth, or cauterise a Wraith in the Black Tower. In fact, live out the fantasies you've only dared dream about. BUT BEWARE ... more die than live to tell the tale! Program requires XB and 32K memory. To run the program, load and run the file RUN. Files must be on a disk named THE_VALLEY. Developed and tested on a console with 32K × 16 bit RAM and CF7+ Compact Flash Drive. Tested on the Win994a simulator. |
| This project is an EPROM Programmer to read and program TMS 2708 (1K × 8) and TMS 2716 (2K × 8) EPROMs Note 1. It was developed to program EPROMs for my TM 990 system. The circuit is based around a TMS 9901 Programmable Systems Interface IC which is used to apply address, data and control signals to the EPROM. A control program, written in assembly language, enables the user to view the data on an EPROM as both hex and ASCII, to verify that an EPROM is blank, to save the data from an EPROM to a data file, to save an EPROM image in memory to a data file, to program an EPROM from a data file, and to compare the data on an EPROM with a data file. The board is designed to plug into the TI-99/4A console side port via a Y-cable (side port splitter), which allows the PEB or other storage device to also be connected at the same time Note 2. The board requires a +12V supply, which can be provided by fitting a DC power socket to the side of the console, wired directly to the +12V supply from the internal power supply board. A circuit diagram of the EPROM Programmer is available here. The object code for the control program Note 3 is available here (disk in V9T9 format; load program EPROM/O using Editor/Assembler option 3). Screenshots of the control program in use are shown below - click each for a larger image. |
![]() |
Note 1: Texas Instruments TMS 2716 EPROMs have a different pinout and programming requirements from 2716 EPROMs from other manufacturers. The board is compatible with TMS 2716 EPROMs from Texas Instruments only.
Note 2: The board and software have been developed using a TI-99/4A with a CF7+ Compact Flash Drive for program storage. It has not been tested with a PEB attached, but there is no reason why it should not work. Note also that I found the CF7+ Compact Flash Drive a bit temperamental connected to the Y-cable as supplied. I ended up shortening the 'arm' of the cable that the CF7+ was connected to, and it then worked perfectly. Positioning the two arms of the Y-cable at 90° to each other may also be sufficient for reliable operation.
Note 3: The algorithm to program an EPROM contains some timing loops which control the application of the +26V programming pulses. The object code compiled here is for a TI-99/4A with 32Kbyte RAM on the internal 16-bit data bus. If the program is to be used on a console with external 32Kbyte RAM (on a CF7+ or in the PEB for example), these programming pulses will be extended (as the console is running slower), but an EPROM will probably still program reliably.
This CF To Disk Transfer Utility helps you copy disk volumes between a CF card and your hard drive. It is in essence a graphical front end to the cf2dsk.exe and dsk2cf.exe programs supplied with the TI-99/4A Compact Flash Drive. Full details are available in this readme file.
(The files originally provided with the CF7+ drive can be downloaded here. Note that the CF7+ drive designer's support e-mail address is no longer working.)
The Line-By-Line Assembler (LBLA) provided on cassette tape with the TI-99/4A Mini Memory module contains a bug, whereby if assembling instructions with two symbolic addressing operands (for example MOV @L1,@L2), and both operands are unresolved references (that is, L1 and L2 in the previous example have not yet been defined), the first instruction will be assembled correctly, but further instructions will not as the label for the second operand is not added to the symbol table, and hence is not 'filled in' when the label is defined later.
The bug is in a small loop starting at address >7248 that clears memory addresses >7194 - >719F after assembling each instruction. This loop also needs to clear one extra word (address >71A0) as this word is used when assembling an instruction to record whether the second operand is an unresolved symbolic reference or not. The bug can be fixed by simply increasing the loop counter by 1, as follows:
Introduction
Software cartridges can contain up to 8Kbyte of ROM, which is decoded in the console to appear in the TI-99/4A memory map address range >6000 - >7FFF. A bank-switching technique can be used in a cartridge to 'page' different banks of a larger ROM into the >6000 - >7FFF address space. Such a cartridge requires additional hardware (self-contained in the cartridge) to control the paging. This can then be used in the following ways:
Implementing Bank Switching in a Cartridge
One method of implementing bank switching is to latch one or more low-order address lines when writing to the cartridge, and to apply these latched bits to the ROM high-order address lines to select different 8Kbyte banks. By writing to different specific addresses, different binary codes can be latched from the low-order address lines, and hence different binary codes can be applied to the ROM high-order address lines to select specific 8Kbyte banks. Writing to a ROM obviously has absolutely no effect on the data stored in the ROM. A circuit diagram of such an implementation is shown below, followed by a detailed description of how the circuit works when selecting a ROM bank. The circuit is from Jon Guidry, who has continued the design work of others and has had PCBs manufactured and cartridge kits made up for home assembly.

The circuit uses a 74LS379 device to latch one or more low-order address lines. For a 16Kbyte ROM, one address line needs to be latched, which gives 2 banks of 8Kbyte. For a 32Kbyte ROM, two address lines need to be latched, which gives 4 banks of 8Kbyte, and so on. The latch is clocked by the WE* line and enabled by the ROMG* line so that the device latches the address lines only on write operations to the >6000 - >7FFF address range. The ROM high-order address lines are fed from the latch Qx* outputs; there appears to be no particular reason why the latch's inverted outputs are used - it is possibly for compatibility with earlier designs. Processor address line A15 is not latched because of the word-based nature of the processor - A15 is toggled both high and low during a single memory write operation.
Selecting a ROM Bank
To select a ROM bank, a word of data (any data, it doesn't matter) has to be written to a specific address in the >6000 - >7FFF address range. At circuit level, this is what happens:
When an address in the cartridge ROM is read, the processor sets up the read address on the address bus A0 - A15, and brings *MEMEN low which brings *ROMG low. This enables the 74LS379, so as described before, it presents the address bits last latched (clocked) on the Qx* outputs. The ROM is now seeing 13 address lines from the console (which select an address within the 8Kbyte address space), plus another one or more address lines from the 74LS379 (which select an 8Kbyte bank within the ROM). These address lines are addressing a specific byte in the ROM, and as the ROM CS* line is low (because it is connected to ROMG*) the ROM outputs the data stored at that address to be read by the processor.
To select a ROM bank, a word of data has to be written to a specific address in the >6000 - >7FFF address range. To calculate the address to write to to select a particular bank, the following logic applies:
<-A0 A15->
011x xxxx xxxx 111x will select bank 0
011x xxxx xxxx 110x will select bank 1
... up to ...
011x xxxx xxxx 001x will select bank 6
011x xxxx xxxx 000x will select bank 7
'x' can be either a 1 or a 0 - it doesn't matter to the latch - but for convention assume they are 0.
So, writing to address:
<-A0 A15->
0110 0000 0000 1110 = >600E will select bank 0
0110 0000 0000 1100 = >600C will select bank 1
... up to ...
0110 0000 0000 0010 = >6002 will select bank 6
0110 0000 0000 0000 = >6000 will select bank 7
As 'x' can be either a 1 or a 0, banks can be selected at other addresses as well ...
<-A0 A15->
0111 1111 1111 1111 = >7FFF will select bank 0
0111 1111 1111 0001 = >7FF1 will select bank 7
... but it makes sense to stick to a convention of having 'x' as 0.
To select a bank in assembly language, any of the following will work (just substitute >600E for the appropriate address of the bank to select):
| MOV R0, @>600E | (writes the value in R0 to the ROM; the value in R0 is immaterial) |
| CLR @>600E | (writes the value 0 to the ROM) |
| MOV @>600E,@>600E | (reads from the ROM, then does a write) |
Sample Code for Cartridge Header to Copy Cartridge Memory Banks to 32K Memory Expansion
The following code is for a cartridge header which copies code from a 2-bank cartridge to the 32K memory expansion, then branches to an address in the memory expansion to run it.
********************************
* JON GUIDRY - MARCH 2009 *
* ROM CARTRIDGE HEADER, *
* 74LS379 BANK SWITCH ROUTINE, *
* & COPY/EXECUTE @ >A000 *
* 9900 ASSEMBLY LANGUAGE *
********************************
* THANKS TO TURSI, STUART *
* CONNER, AND BOB CARMANY *
* FOR THE HELP! *
********************************
* BANK 0/1 ROM HEADER FOR 16K BANKED
* SWITCHED CART
DEF SFIRST,SLAST,SLOAD
UNL
* ROM HEADER
AORG >6000 * START ADDRESS OF CARTRIDGE ROM
SFIRST EQU $
SLOAD EQU $
GRMHDR BYTE >AA * INDICATES A STANDARD HEADER
BYTE >01 * VERSION NUMBER
BYTE >01 * NUMBER OF PROGRAMS (OPTIONAL)
BYTE >00 * NOT USED
DATA >0000 * POINTER TO POWER-UP LIST (CAN'T USE IN CARTRIDGE ROM)
DATA PROG * POINTER TO PROGRAM LIST
DATA >0000 * POINTER TO DSR LIST
DATA >0000 * POINTER TO SUBPROGRAM LIST
DATA >0000
DATA >0000
PROG DATA >0000 * NO NEXT MENU ITEM
DATA MAIN * PROGRAM START ADDRESS FOR THIS MENU ITEM
BYTE 12 * LENGTH OF TEXT FOR MENU SCREEN
TEXT 'PROGRAM NAME'
EVEN
* THIS IS THE ROUTINE THAT WILL
* SWAP BANKS TO HIGH BANK & COPY
MAIN EQU $
LWPI >8300
MOV R0,@>6000 * SELECT BANK
LI R4,>0740 * NUMBER OF BYTES TO COPY, DIVIDED BY 4
LI R9,>6300 * ADDRESS TO COPY FROM
LI R10,>A000 * ADDRESS TO COPY TO
LP1
MOV *R9+,*R10+
MOV *R9+,*R10+
DEC R4
JNE LP1
* THIS IS THE ROUTINE THAT WILL
* SWAP BANKS TO LOW BANK & COPY
MAIN2 MOV R0,@>6002
LI R4,>0740
LI R9,>6300
LI R10,>BD00
LP2
MOV *R9+,*R10+
MOV *R9+,*R10+
DEC R4
JNE LP2
* ALRIGHT, WE'RE DONE. LET'S GO!
B @>A000
FINISH EQU $
SLAST END