Page Contents

small arrow Description
small arrow Programs
small arrow EPROM Programmer
small arrow Compact Flash Drive Utility
small arrow Mini Memory Module Line-By-Line Assembler Bug
small arrow Cartridge Bank Switching

Description

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.

TI-99/4A photo For a full description of the system, see this comprehensive Wikipedia entry. TI-99/4A start screen

Programs

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.

The Valley - splash screen The Valley - main screen The Valley - Black Tower of Zaexon

EPROM Programmer

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.
EPROM Programmer PCB

EPROM Programmer - menu EPROM Programmer - verify EPROM is blank EPROM Programmer - view EPROM data EPROM Programmer - programming EPROM

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.

Compact Flash Drive Utility

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.)

Mini Memory Module Line-By-Line Assembler Bug

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:

  1. Load the LBLA in the normal way using Easy Bug.
  2. After loading, while still in Easy Bug, type M724F followed by the <Enter> key.
  3. The value 06 should be displayed. Type 07 followed by the <Enter> key.
  4. Press the '.' key to return to the Easy Bug prompt.
  5. Type S7000 followed by the <Enter> key to save the corrected program back to cassette tape.

Cartridge Bank Switching

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.

Bank switching circuit diagram

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:

  1. The processor sets up the write address on its address bus A0 - A15. (It also sets the data up on the data bus but that is irrelevent at the moment.) It also brings its MEMEN* signal low - this is not shown in the circuit diagram, but that action in the console brings the ROMG* signal low (assuming the write address is an address in the cartridge address space), so the 74LS379 latch is now 'enabled' - meaning it is outputting signals on its Qx and Qx* outputs and will respond to the clock input.
  2. With the address bus now set up, the processor pulses WE* low. This clocks the 74LS379, so whatever binary code the device is seeing on its Dx inputs it presents on it Qx outputs, with inverted signals on the Qx* outputs. Each time the 74LS379 is enabled in the future, this same binary code will be presented on the outputs again until the device is clocked again to latch a (possibly) different binary code.
  3. The processor now brings MEMEN* high, which brings ROMG* high to disable the 74LS379, and performs the next instruction.

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:

  1. Consider a 64Kbyte ROM which uses 3 latched address lines, giving 8 banks. Number the banks 0 - 7.
  2. Take the number of the bank required, in binary, and invert it (because the circuit uses the 74LS379 inverted Qx* outputs rather than the Qx outputs). So bank 0 is 111, bank 1 is 110, bank 2 is 101, and so on.
  3. Specify the inverted number of the bank required on processor address lines A12 - A14. Also, address lines A0 - A2 have to be 011 to select the cartridge space >6000. So, address:

<-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

back to home page