Description
Programs
EPROM Programmer
Compact Flash Drive Utility
Mini Memory Module Line-By-Line Assembler Bug
Cartridge Bank Switching
Resurrecting a TI Disk System
Connecting a Serial Mouse
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: Cortex_BASIC.zip (V9T9/.tidisk and FIAD formats) | |||||||||||||||||||||||||||||||||||||||
|
This is a port of the 'Power BASIC' interpreter used with the TMS9995-based Powertran Cortex machine. Features and constraints are as follows:
The Cortex BASIC user guide is available which details the Cortex BASIC implementation. This document was recreated by Jim Fetzner from a poor quality photocopy. I’m looking to do a further release which includes having it run from one of Jon Guidry’s bank switched cartridges where it will unload itself from the cartridge into RAM and run mainly from there, but by having some code remaining running from the cartridge it should be possible to free up another 8K of RAM or so for program and variable storage. Running it with an 8K E/A SuperCart might also be an option. Code for direct control of the RS-232 and parallel port hardware (bypassing use of the DSRs) is also available, but including this will obviously reduce the amount of RAM available for program storage. Having it run directly from a bank switching cartridge to free up most of the 32K of RAM is a possibility, but accomplishing this is a non-trivial task due to the way some of the routines are nested and modify their return addresses. Loading the Program Download the .zip file. I'm assuming you know how to get the relevant file onto a real hardware storage device. If using Classic99, save the CBASIC file (no extension) from the .zip file into a simulator disk folder. Then switch on with the Editor/Assembler cartridge, select E/A option 3 and type the filename DSKn.CBASIC. The program should load and display the *Ready prompt within a few seconds. Keyboard Mapping
Changes and Restrictions in the TI Implementation There are some changes and restrictions in the TI implementation as compared to the implementation described in the Cortex user guide. Note that some commands work differently to their familiar equivalents in TI BASIC. If you think you've found a bug in the interpreter code, download the Cortex simulator (written by David Hunter) and check your program on there (note though that the simulator doesn't support GRAPHics mode at the moment). You can report any confirmed bugs to me at ti99(at)stuartconner(dot)me(dot)uk.
|
|||||||||||||||||||||||||||||||||||||||
| Revisions 1.0 - 29 Jan 2011 - Initial release. 1.1 - 10 Feb 2011 - Added load/save functionality. 1.2 - 17 Feb 2011 - Moved most processor workspaces to 16-bit 256-byte console RAM to increase speed. 1.3 - 01 Apr 2011 - Improved key handling with the KEY() function, which would previously miss some key strokes. To check for keys pressed in a game for example, call NOESC at the start of the program, then A=KEY(0) to check for a key press, and IF A=01BH THEN STOP as part of the key handling routine to enable <Escape>ing out of the program. |
|||||||||||||||||||||||||||||||||||||||
| Disk: Miscellaneous.zip (V9T9/.tidisk 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. The following RAM image files can be loaded using the CART_RAM/O program: |
| 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 (LBLA). Program names: OLD, NEW. |
| MM_LINES | Data file containing the RAM image for the MiniMem Lines demonstration program. Program name: LINES. To load and run the MiniMem LBLA for example: (1) Download the Miscellaneous.zip file from the link above, unzip it, and make a disk out of the file. (In the case of a CF7+/nanoPEB device, copy the file onto the CF card using the PC and the file transfer utilities provided with the device.) (2) Insert the MiniMem cartridge, then from the title screen select option 3 then option 1, and specify file DSK1.CART_RAM/O (substitute DSK1 for whichever disk drive you're using). If this gives a Memory Full or Duplicate Definition error, reset the console, select option 3 then option 3 then press the <Proceed> key to reinitialise the MiniMem RAM, and start again. (3) When the program loads and runs, select option 2 and specify file DSK1.MM_LBLA. When this has loaded, select option 4 to reset the console. (4) From the title screen, select option 3 then option 2, and specify program name NEW. The LBLA screen should now be displayed ready for input. |
| 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/.tidisk 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 (including how to run the utility and the cf2dsk.exe and dsk2cf.exe programs under Windows 7). (The files originally provided with the CF7+ drive can be downloaded here or from the designer's website.) |
![]() |
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
| Most TI disk systems use either a sidecar disk drive controller (PHP1800) or a disk drive controller expansion card (PHP1240) mounted in a peripheral expansion box (PEB). This section covers a third option - a disk drive controller expansion card connected directly to the console using a special ribbon cable. This was purchased off eBay having previously been acquired from a woman whose husband worked for TI. A thread about the system on one of the TI-99 forums suggests that the special ribbon cable may have been made at the TI-99 European research centre at Almelo in the Netherlands. As well as the ribbon cable and disk drive controller, two Siemens FDD200-5 floppy drives were included in the purchase. These are DSDD drives, but the disk controller limits their use to DSSD. The drives are mounted in a rather handy chassis that has been reused from some other piece of equipment. | ![]() |
| The ribbon cable has a connector at each end, one to mate with the console side port, and the other with the same pinout as the expansion card connectors in the PEB. The connectors are mounted in paxolin blocks which have been cut, milled and drilled - very tidy work. The 5-pin DIN plug is for connecting an external power supply to power the disk controller card. The whole arrangement is entirely passive apart from five 47Ω pullup resistors (to +5V) on pins 12, 16, 45, 46, 48 at the expansion card end which perform the function of those normally found on the flex cable interface card in the PEB (the flex cable interface card also has pullup resistors on pin 13 and 15, but these pins are not connected through the ribbon cable). Further detailed photos of the ribbon cable can be seen here, here and here. The connections between the two connectors on the ribbon cable are detailed in the table further down this page. The sliding door has to be removed from the console side port to enable the connector at the console end of the cable to fit, and the connector wiggled a little so it slips past the metal earthing fingers each side of the console connector. The disk controller card has been modified to disconnect the +5V, +12V and -5V voltage regulators and strap the power supplies straight through onto the card, allowing the use of an external regulated power supply. A few of the TTL ICs are socketed and presumably have been replaced at some point in the past. A picture of a standard card is available here. |
Getting the disk system to work proved to be an interesting experience ...
First I had to disassemble the disk controller end of the cable to determine the wiring to the DIN plug used for power to the disk controller. As the disk controller card has been modified to accept regulated supplies directly, it can be conveniently powered from an old PC ATX power supply that can also power the floppy drives themselves, so I wired up a DIN plug to connect with the power plug at the end of the cable.
So with the cable connected to the console, power connected to the cable, but the disk controller card not connected, the console boots fine. Connect the disk controller card however and the console hangs immediately power is applied. So out with the multimeter and check for shorts to ground on each of the disk controller card connector pins. This reveals that the READY signal has a resistance of only 20Ω to ground. It is driven by a 74LS125, so remove the old one, fit a socket and pop a new one in. The console now boots fine with the disk controller connected.
Powering on the console doesn't give the usual brief flash from the disk controller card LED as the DSR power up routine is executed. So out with the MiniMem cartridge and use EasyBug to 'switch on' the card by writing a 1 to CRU address >1100. The disk controller card LED now lights so it looks like the CRU circuit is working. Now looking at memory locations >4000 onward should read the DSR from the disk controller card ROMs, but only 00s are returned. So use the logic probe to start checking the inputs to the PAL U18; nothing obviously wrong here from a quick check. Checking the PAL outputs, the logic probe doesn't give a signal on the line to the 74LS245 data buffer U3 /OE pin. Checking this with a multimeter shows a voltage of ~1.8V, in the indeterminate range between a logic 0 and a logic 1. The 'LS245 is already socketed (and heatsinked via a small block of aluminium stuck to the inside of the clam shell) so has been replaced before – this particular type of IC can be prone to failure. Remove it and the output from the PAL starts registering on the logic probe. Checking the 'LS245 itself, the /OE pin has a resistance of approximately 80Ω to ground, so replace that, and the output from the PAL still registers on the logic probe. Still no joy though reading the contents of the disk controller card DSR ROMs. Looking at the inputs to the PAL a bit closer, there is no activity on the /MEMEN input. Tracing this signal back, the /MEMEN input to the 74LS244 buffer U5 is floating – the signal is not getting down the cable from the console. Take the cable connectors apart again to trace the signal through the cable, and /MEMEN is routed down the outer-most wire on one edge of the ribbon cable. This had been trapped years before when the connectors were assembled – the cable wasn't quite aligned in the shallow cutout between the two halves of the block, and the insulation was completely flattened. I had noticed this before, but hadn't thought that the wire within could also be broken, which it actually was. I managed a neat repair with a short length of wire from a spare piece of ribbon cable. Everything assembled again, power on the console and the disk controller card LED now gives the usual brief flash, and using EasyBug I can now read the contents of the DSR ROMs.
Next stage is to look at the drives. First, on one of the drives the sector mark sensor (photodiode) has broken off its base and this is fixed with a little bit of glue.
So, connect power to the first drive and switch on. Smoke! Resistor R22 on the floppy PCB is glowing gently red! Oh dear. Let's try the second drive. Smoke! Resistor R22 on the second drive is also gently glowing. Checking both boards, one side of R22 is shorted to ground, and the culprit – electrolytic capacitor C3 has shorted on *both* boards. Snipping one end of C3 temporarily allows testing to continue; I'll replace them and the charred resistors later. Experimenting with the drives, which are double-sided, yields the following results: on one drive only the bottom head is working (will only format single-sided), and on the second drive, both heads appear to be working (can format double-sided). The PCB on one of the drives is also faulty – any disk operation gives disk error 16 "no disk or no drive". Looking at the circuit diagram (a comprehensive instruction manual for the Siemens FDD200-5 drive is included in the manual for the Siemens PU 670C Programming Unit), the outputs from the floppy drive to the controller are all open-collector and gated by the drive select signal so that multiple drives can be connected on the same ribbon cable. Checking a few of the outputs with the logic probe while trying to access the drives – nothing. Tracing the drive select signal through the circuit identifies a 74LS14 inverter with a stuck output so remove it, fit a socket and pop a new one in and both drives now working.
Running the Disk Manager comprehensive test on each drive for a while reveals no further problems.
Ribbon Cable Connections
The connections between the two connectors on the ribbon cable are detailed in the table below.
Remember that you will need to provide a power source for the expansion card, either supplies at the same voltages as the PEB if leaving the voltage regulators in the expansion card in place, or regulated 5/12V supplies if bypassing the regulators in the card. Check and check again that the power supplies are correct before connecting!
| Expansion Card Connector |
Console Side Port Connector |
||
| 60 | +12V regulator supply | ||
| 59 | +12V regulator supply | ||
| 58 | -12V regulator supply | ||
| 57 | -12V regulator supply | ||
| 56 | /MEMEN -------------------------------------------- | 32 | |
| 55 | CRUIN ------------------------------------------------ | 33 | |
| 54 | /WE --------------------------------------------------- | 26 | |
| 53 | --- N/C (GND) | ||
| 52 | DBIN -------------------------------------------------- | 9 | |
| 51 | /CRUCLK -------------------------------------------- | 22 | |
| 50 | /CLKOUT -------------------------------------------- | 24 | |
| 49 | --- N/C (GND) | ||
| 48 | Pullup to +5V (AMC) | ||
| 47 | GND --------------------------------------------------- | 23 | |
| 46 | Pullup to +5V (AMA) | ||
| 45 | Pullup to +5V (AMB) | ||
| 44 | A1 ------------------------------------------------------ | 30 | |
| 43 | A0 ------------------------------------------------------ | 31 | |
| 42 | A3 ------------------------------------------------------ | 10 | |
| 41 | A2 ------------------------------------------------------ | 20 | |
| 40 | A5 ------------------------------------------------------ | 5 | |
| 39 | A4 ------------------------------------------------------ | 7 | |
| 38 | A7 ------------------------------------------------------ | 17 | |
| 37 | A6 ------------------------------------------------------ | 29 | |
| 36 | A9 ------------------------------------------------------ | 18 | |
| 35 | A8 ------------------------------------------------------ | 14 | |
| 34 | A11 ---------------------------------------------------- | 8 | |
| 33 | A10 ---------------------------------------------------- | 6 | |
| 32 | A13 ---------------------------------------------------- | 15 | |
| 31 | A12 ---------------------------------------------------- | 11 | |
| 30 | A15 /CRUOUT ------------------------------------- | 19 | |
| 29 | A14 ---------------------------------------------------- | 16 | |
| 28 | D0 ------------------------------------------------------ | 37 | |
| 27 | --- N/C (GND) | ||
| 26 | D2 ------------------------------------------------------ | 39 | |
| 25 | D1 ------------------------------------------------------ | 40 | |
| 24 | D4 ------------------------------------------------------ | 35 | |
| 23 | D3 ------------------------------------------------------ | 42 | |
| 22 | D6 ------------------------------------------------------ | 36 | |
| 21 | D5 ------------------------------------------------------ | 38 | |
| 20 | --- N/C (GND) | ||
| 19 | D7 ------------------------------------------------------ | 34 | |
| 18 | --- N/C (/LOAD) | ||
| 17 | --- N/C (/INTA) | ||
| 16 | Pullup to +5V (/SENILB) | ||
| 15 | --- N/C (/SENILA) | ||
| 14 | --- N/C (IAQHA) | ||
| 13 | --- N/C (/HOLD)) | ||
| 12 | Pullup to +5V (PCBEN) | ||
| 11 | --- N/C (/RDBENA) | ||
| 10 | --- N/C (AUDIOIN) | ||
| 9 | --- N/C (/LCP) | ||
| 8 | --- N/C (SCLK) | ||
| 7 | --- N/C (GND) | ||
| 6 | /RESET ---------------------------------------------- | 3 | |
| 5 | --- N/C (GND) | ||
| 4 | READY ---------------------------------------------- | 12 | |
| 3 | GND -------------------------------------------------- | 21 | |
| 2 | +5V regulator supply | ||
| 1 | +5V regulator supply | ||
| A standard, old PC serial mouse can be connected directly to the serial port on a TI-99/4A nanoPEB interface. The listing below is for a mouse-driven menu and a simple sketch program. The listing also provides an example of how to initialise and control the RS-232 port, and how to plot individual pixels with the TMS 9918A VDP in graphics 2 mode. There is a video of the program in use here. I've tried two serial mice which both work - labelled on the bottom as a Microsoft "Serial Mouse 2.1A", and a Microsoft "Serial - PS/2 Compatible Mouse". |
![]() |
******************************************************************************
*Experiment using a PC serial mouse connected to the serial port on a NanoPEB.
*The program first displays a mouse-driven menu, which is configured in
*Graphics 1 mode and uses a sprite defined as the mouse pointer. Selecting the
*first menu option runs a simple sketch application which is configured in
*Graphics 2 mode, giving a resolution of 256 x 192. Instructions for using the
*sketch application are displayed on screen.
*
*Mouse protocol details reference: www.kryslix.com/nsfaq/Q.12.html
*TMS9918A VDP datasheet: ftp://ftp.whtech.com/datasheets%20and%20manuals/
* Datasheets%20-%20TI/TMS9918.pdf
******************************************************************************
AORG >A000
DEF START
REF VSBW VDP single byte write.
REF VMBW VDP multiple byte write.
REF GPLLNK GPL routine link.
*************
*Definitions.
*************
*Graphics 1 mode storage in VRAM.
PNTBA1 EQU >0000 Pattern name table base address.
PGTBA1 EQU >0800 Pattern generator table base address.
CTBA1 EQU >0380 Colour table base address.
SATBA1 EQU >1B00 Sprite attribute table base address.
SGTBA1 EQU >3800 Sprite generator table base address.
*Graphics 2 (bitmap) mode storage in VRAM.
PNTBA2 EQU >1800 Pattern name table base address.
PGTBA2 EQU >0000 Pattern generator table base address.
CTBA2 EQU >2000 Colour table base address.
SATBA2 EQU SATBA1 Sprite attribute table base address.
SGTBA2 EQU SGTBA1 Sprite generator table base address.
*Memory mapped I/O definitions.
VDPREG EQU >8C02 VDP VRAM address and register access address.
VRAMW EQU >8C00 VDP VRAM data write address.
VRAMR EQU >8800 VDP VRAM data read address.
*CRU base address definitions.
BACARD EQU >1300 NanoPEB serial interface base address.
BA9902 EQU >1340 NanoPEB serial port 1 base address.
*******
*Start.
*******
START LWPI MYWS Load workspace.
******************************
*Initialise mouse RS-232 port.
******************************
*Switch on serial interface.
LI R12,BACARD
SBO 0
*Set port 1 to 1200 Baud, 7 data bits, no parity, 1 stop bit.
LI R12,BA9902 CRU base address of 9902 in NanoPEB.
SBO 31 Reset 9902. This sets /RTS inactive high, so the
* RTS output line to -ve voltage.
LI R1,>8200 Control register: 1 stop bit, no parity, 7 data
* bits (binary 10000010).
LDCR R1,8 Load control register.
SBZ 13 Disable loading of interval register.
LI R1,>01A0 1200 Baud.
LDCR R1,12 Load transmit and receive data rate registers.
SBO 16 Set /RTS active low, so the RTS output line to +ve
* voltage to power the mouse.
**************************************************************************
*Set up Graphics 1 mode.
*(Will already be in Graphics 1 mode after starting the program from E/A,
* but need routine to set up this mode when returning to the menu from the
* mouse drawing program which uses Graphics 2 mode.)
**************************************************************************
*Load VDP registers.
GRAPH1 BL @LOADER
BYTE >00,>80 Register 0 - graphics 1 mode, external video off.
BYTE >E0,>81 Register 1 - 16K, display on, interrupts on,
* graphics 1, size & mag = 0.
BYTE >00,>82 Register 2 - PNTBA1 = >0000. Pattern name table.
BYTE >0E,>83 Register 3 - CTBA1 = >0380. Colour table.
BYTE >01,>84 Register 4 - PGTBA1 = >0800. Pattern generator
* table.
BYTE >36,>85 Register 5 - SATBA1 = >1B00. Sprite attribute
* table.
BYTE >07,>86 Register 6 - SGTBA1 = >3800. Sprite generator
* table.
BYTE >F5,>87 Register 7 - Backdrop=background colour.
DATA 0
*Clear the sprite generator table (SGT) and sprite attribute table (SAT).
BL @CLRSPR
*Load character set (character codes >20 - >5F) (from E/A manual page 251).
CLR R1 Clear GPL STATUS byte.
MOVB R1,@>837C
LI R1,8*>20+PGTBA1 Address in VDP RAM to load character set.
MOV R1,@>834A
BLWP @GPLLNK
DATA >0018
*Load colour table.
LI R8,CTBA1+>4000 Reference CT. Add >4000 for VDP write operations.
BL @SENDAD Send VDP address.
LI R11,256/8 Set count.
LI R1,>F500 Colour - white on light blue.
CTGRH1 MOVB R1,*R7 Write to colour table.
DEC R11 Done all entries?
JNE CTGRH1 No, loop around.
*Redefine characters:
* 96 for the menu selection pointer.
* 97 for inverse video 'H'.
* 98 for inverse video 'E'.
* 99 for inverse video 'R'.
LI R0,96*8+>0800 Offset of >0800 as PGT starts at >0800.
LI R1,MSPDAT
LI R2,8*4
BLWP @VMBW
*********************************
*Display menu in Graphics 1 mode.
*********************************
*Clear screen.
MNMENU BL @CLRSCN
*Display menu text.
CLR R0
LI R1,TXT1
MOV @TXT1L,R2
BLWP @VMBW
LI R0,32*3
LI R1,TXT2
MOV @TXT2L,R2
BLWP @VMBW
***********************************************************
*Define mouse pointer sprite and place at middle of screen.
***********************************************************
BL @DEFMSE
*Initialise mouse position to the middle of the screen.
*Mouse position range is twice the screen resolution (twice 192 x 256) to get
*an adequate movement of the mouse. The mouse position will be divided by two
*to map it to screen coordinates. (Can't divide mouse movement by two
*otherwise very slow movement will result in no movement.)
LI R9,256/2*2 Mouse X position in LSB.
MOV R9,@MSXPOS
LI R9,192/2*2 Mouse Y position in LSB.
MOV R9,@MSYPOS
**********************************************************************
*Get mouse position and display indicator against menu option if mouse
*Y position is on the same line.
**********************************************************************
GMPOS BL @UPDTMS Update mouse position.
MOV @MSYPOS,R9 Get mouse Y position.
SRL R9,4 Divide by 2, then by 8 to convert from pixels
* to lines.
LI R4,3 Menu start line number.
LI R5,6 Menu end line number.
LI R0,3*32+2 Menu pointer display position for top line.
MEN01 LI R1,' '*256 Default to no menu pointer for this line.
C R9,R4 Mouse on this line?
JNE MEN02 No, jump.
LI R1,96*256 Yes, select menu selection pointer character.
MEN02 BLWP @VSBW Display or remove menu pointer for this line.
C R4,R5 Done last line of menu?
JEQ CHKBTN Yes, jump.
AI R0,32 No, do next line of menu.
INC R4
JMP MEN01
************************************************************
*Mouse left button clicked? If yes then jump to menu option.
************************************************************
CHKBTN MOV @MSBTTN,R1
COC @H6000,R1 Check for left mouse button pressed.
JNE GMPOS Left button not pressed, jump.
CI R9,3 Button pressed when on first line of menu?
JEQ MENU01 Yes, jump to menu.
CI R9,4 Button pressed when on second line of menu?
JEQ MENU02 Yes, jump to menu.
CI R9,5 -- Ditto --
JEQ MENU02
CI R9,6
JEQ MENU02
JMP GMPOS Button not pressed when mouse on menu line.
********************
*Menu option 1 text.
********************
*Clear screen.
MENU01 BL @CLRSCN
*Display instruction text for paint program.
CLR R0
LI R1,TXT3
MOV @TXT3L,R2
BLWP @VMBW
LI R0,32*3
LI R1,TXT4
MOV @TXT4L,R2
BLWP @VMBW
LI R0,32*23+5
LI R1,TXT6
MOV @TXT6L,R2
BLWP @VMBW
*Loop until mouse clicked on 'HERE' on bottom line.
BL @WAITHR
*Jump to drawing program.
JMP RSTART
*************************
*Menu options 2 - 4 text.
*************************
*Clear screen.
MENU02 BL @CLRSCN
*Display 'menu option not implemented' text.
CLR R0
LI R1,TXT5
MOV @TXT5L,R2
BLWP @VMBW
LI R0,32*23+5
LI R1,TXT6
MOV @TXT6L,R2
BLWP @VMBW
*Loop until mouse clicked on 'HERE' on bottom line.
BL @WAITHR
*Return to main menu.
JMP MNMENU
******************************************************************************
* MOUSE DRAWING PROGRAM *
******************************************************************************
************************
*Set up Graphics 2 mode.
************************
*Load VDP registers.
RSTART BL @LOADER
BYTE >02,>80 Register 0 - graphics 2 mode, external video off.
BYTE >80,>81 Register 1 - 16K, no display, no interrupt,
* graphics 2, size & mag = 0.
BYTE >06,>82 Register 2 - PNTBA2 = >1800. Pattern name table.
BYTE >FF,>83 Register 3 - CTBA2 = >2000. Colour table.
BYTE >03,>84 Register 4 - PGTBA2 = >0000. Pattern generator
* table.
BYTE >36,>85 Register 5 - SATBA2 = >1B00. Sprite attribute
* table.
BYTE >07,>86 Register 6 - SGTBA2 = >3800. Sprite generator
* table.
BYTE >00,>87 Register 7 - Backdrop=background colour.
DATA 0
*Clear the sprite generator table (SGT) and sprite attribute table (SAT).
BL @CLRSPR
*Set up pattern name table.
LI R8,PNTBA2+>4000 Reference PNT. Add >4000 for VDP write
* operations.
BL @SENDAD Send VDP address.
SETO R11 Reset count.
INIPNT INC R11 Next pattern.
SWPB R11 Position LS byte.
MOVB R11,*R7 Write it.
SWPB R11 Restore R11.
CI R11,3*256 Done all entries?
JL INIPNT No, loop around.
*Set up pattern generator table.
LI R8,PGTBA2+>4000 Reference PGT. Add >4000 for VDP write
* operations.
BL @SENDAD Send VDP address.
LI R11,3*256*8 Set count.
KILPGT MOVB @B00,*R7 Reset entry.
DEC R11 Done all entries?
JNE KILPGT No, loop around.
*Set up colour table.
LI R8,CTBA2+>4000 Reference CT. Add >4000 for VDP write operations.
BL @SENDAD Send VDP address.
CLR R1 Clear R1 because we'll be shifting left.
MOVB @MPTSAT+3,R1 Get initial mouse pointer sprite colour.
SLA R1,4 Shift to left nibble to align with foreground
* colour in CT.
MOVB R1,@MSCOL Store initial mouse pointer colour.
LI R11,3*256*8 Set count.
INICT MOVB R1,*R7 Set colour to initial mouse pointer sprite colour.
DEC R11 Done all entries?
JNE INICT No, loop around.
*Re-enable display.
BL @LOADER
BYTE >C0,>81
DATA 0
***********************************************************
*Define mouse pointer sprite and place at middle of screen.
***********************************************************
BL @DEFMSE
LI R9,256/2*2 Mouse X position in LSB.
MOV R9,@MSXPOS
LI R9,192/2*2 Mouse Y position in LSB.
MOV R9,@MSYPOS
***********************
*Update mouse position.
***********************
WAIT1 BL @UPDTMS
*************************************************************************
*Check for left and right buttons pressed together. If pressed, return to
*main menu.
**************************************************************************
MOV @MSBTTN,R1
COC @H7000,R1 Check for left and right button indication in 1st
* byte received.
JNE CLRSCR Left and right button not both pressed, jump.
B @GRAPH1 Return to main menu.
***********************************************************************
*Check for right button press. If pressed, change mouse pointer colour.
***********************************************************************
CLRSCR COC @H5000,R1 Check for right button indication in 1st byte
* received.
JNE UPDCL1 Right button not pressed, jump.
AB @H10,@MSCOL Right button pressed. Move onto next colour.
JNE UPDCOL Need to wrap colour index back round? No, jump.
MOVB @H20,@MSCOL Reset colour to 2, skipping transparent and black
* colours.
UPDCOL LI R8,SATBA2+>4000+3 Reference colour byte in SAT. Add >4000 for
* VDP write operations.
BL @SENDAD Send VDP address.
MOVB @MSCOL,R2 Get stored colour.
SRL R2,4 Shift to 2nd nibble to align with colour nibble in
* SAT.
MOVB R2,*R7 Write new colour to mouse pointer sprite.
***********************************************************************
*Check for left button press. If pressed, draw pixel at mouse position.
***********************************************************************
UPDCL1 COC @H6000,R1 Check for left button indication in 1st byte
* received.
JNE DRWEX Left button not pressed, jump.
*Convert mouse X position to column number and remainder.
MOV @MSXPOS,R2 Get X position (which is at twice screen
* resolution).
MOV R2,R3 Copy it.
SRL R2,4 Divide by 2 to convert to screen resolution, then
* divide by 8 to get column number.
SRL R3,1 Divide by 2 to convert to screen resolution.
ANDI R3,>0007 Get 3 LS bits which are the remainder
* (the pixel 0 to 7 within the 8-pixel column).
*Convert mouse Y position to row number and remainder.
MOV @MSYPOS,R8 Get Y position (which is at twice screen
* resolution).
MOV R8,R9 Copy it.
SRL R8,4 Divide by 2 to convert to screen resolution, then
* divide by 8 to get row number.
SRL R9,1 Divide by 2 to convert to screen resolution.
ANDI R9,>0007 Get 3 LS bits which are the remainder
* (the pixel 0 to 7 within the 8-pixel row).
*Multiply row number by 32, then add column number to get cell number.
SLA R8,5 Multiply row number by 32.
A R2,R8 Add column number.
*Multiply cell number by 8 to get index into entry in the PGT for this cell
*(8 bytes in PGT per cell, 1 per pixel row).
SLA R8,3 Multiply cell number by 8.
*Get current VRAM data from cell number, add new pixel, and write back to
*VRAM.
A R9,R8 Add Y remainder to get correct byte in PGT for the
* pixel row.
BL @SENDAD Send cell address to VDP.
CLR R10 Clear pixel mask register. The pixel mask gives
* the bit to set in the PGT byte for the pixel
* 0 to 7 within the 8-pixel column.
AI R3,MASKTB Add address of pixel mask table base to
* X remainder.
MOVB *R3,R10 Fetch pixel mask.
MOVB @VRAMR,R3 Get current VRAM data.
SOCB R10,R3 Set pixel bit.
ORI R8,>4000 Set VDP write bit in address.
BL @SENDAD Send address to VDP.
MOVB R3,*R7 Write updated VRAM data.
*Set the colour table entry to the current mouse pointer sprite colour.
AI R8,CTBA2-PGTBA2 Get address of PCT entry.
BL @SENDAD Send address to VDP.
MOVB @MSCOL,*R7 Update colour entry.
********************************
*Loop round and do it all again.
********************************
DRWEX B @WAIT1
*************
*************
*Subroutines.
*************
*************
**************************************************
*Load the VDP registers from an inline data table.
**************************************************
LOADER MOVB *R11+,@VDPREG Write register data.
C *R11,*R11 Dummy delay for VDP.
MOVB *R11+,@VDPREG Write register number.
MOV *R11,*R11 End of data table?
JNE LOADER No, loop.
INCT R11 Yes, skip data table terminator.
B *R11 Return.
***********************************
*Send the address in R8 to the VDP.
***********************************
SENDAD SWPB R8 Position LSB.
MOVB R8,@VDPREG Send LSB.
SWPB R8 Position MSB.
MOVB R8,@VDPREG Send MSB.
B *R11 Return.
*************************************************************************
*Clear the sprite generator table (SGT) and sprite attribute table (SAT).
*************************************************************************
CLRSPR MOV R11,@SAVR11 Save return address.
LI R7,VRAMW
LI R8,SGTBA1+>4000 Reference SGT. Add >4000 for VDP write
* operations.
BL @SENDAD Send VDP address.
LI R8,256*8 Do 256 8-bit patterns.
KILSGT MOVB @B00,*R7 Null out the pattern.
DEC R8 Count it.
JNE KILSGT Loop till all done.
LI R8,SATBA1+>4000 Reference SAT. Add >4000 for VDP write
* operations.
BL @SENDAD Send VDP address.
LI R8,32*8 Kill off all 32 sprite planes.
LI R6,>D000 Fill it full of sprite terminators.
KILSAT MOVB R6,*R7 Clear SAT.
DEC R8 Count it.
JNE KILSAT Loop till all done.
MOV @SAVR11,R11 Restore return address.
B *R11 Return.
**************
*Clear screen.
**************
CLRSCN CLR R0 Start writing at start of screen image table.
LI R1,' '*256 Space character.
LI R2,32*24-1 Number of characters to do - but do 1 outside
* loop.
BLWP @VSBW Write one byte.
CLR1 MOVB R1,@VRAMW Write successive bytes without doing a BLWP -
* quicker.
DEC R2
JNE CLR1
B *R11
***********************************************************
*Define mouse pointer sprite and place at middle of screen.
***********************************************************
*Write character pattern to the sprite generator table.
DEFMSE MOV R11,@SAVR11 Save return address.
LI R8,SGTBA1+>4000 Reference SGT. Add >4000 for VDP write
* operations.
BL @SENDAD Send VDP address.
LI R8,8 Do one 8-bit pattern.
LI R6,MPTSPG Pointer to character pattern.
MPTRSG MOVB *R6+,*R7 Write the pattern.
DEC R8 Count it.
JNE MPTRSG Loop till all done.
*Define sprite in the sprite attribute table.
LI R8,SATBA1+>4000 Reference SAT. Add >4000 for VDP write
* operations.
BL @SENDAD Send VDP address.
LI R8,4 4 bytes to write.
LI R6,MPTSAT Pointer to SAT for mouse pointer.
MPTRSA MOVB *R6+,*R7 Write the SAT.
DEC R8 Count it.
JNE MPTRSA Loop till all done.
MOV @SAVR11,R11 Restore return address.
B *R11 Return.
********************************************************
*Wait for a packet of data from the mouse.
*Determine the mouse movement and update mouse position.
*Move mouse pointer sprite.
********************************************************
**
*Wait for and store a packet of 3 bytes. The first byte of each packet should
*be a value greater than or equal to >40. Check for this to keep reception in
*sync.
**
UPDTMS LI R12,BA9902 CRU base address of 9902 in NanoPEB.
CLR R1
CLR R2
CLR R3
WAIT3 TB 21 Receive buffer register full?
JNE WAIT3 No, loop until a character is received.
STCR R1,8 Read character into MSB of R1.
SBZ 18 Reset receive buffer register.
CI R1,>4000 Bit set to indicate first byte in packet?
JL WAIT3 No, get another byte.
WAIT4 TB 21 Receive buffer register full?
JNE WAIT4 No, loop until a character is received.
STCR R2,8 Read character into MSB of R2.
SBZ 18 Reset receive buffer register.
WAIT5 TB 21 Receive buffer register full?
JNE WAIT5 No, loop until a character is received.
STCR R3,8 Read character into MSB of R3.
SBZ 18 Reset receive buffer register.
MOV R1,@MSBTTN Save mouse buttons pressed data.
**
*Determine the mouse movement and update mouse position.
**
*Determine the X movement.
MOV R1,R5 Copy byte 1.
SLA R5,6 Move MS bits of X movement to top of byte.
A R5,R2 Add to rest of X movement in 2nd byte.
SWPB R2 Move result into LSB.
*Determine the Y movement.
MOV R1,R5 Copy byte 1.
ANDI R5,>0C00 Isolate bits 2 and 3.
SLA R5,4 Shift to move MS bits of Y movement to top of
* byte.
A R5,R3 Add to rest of Y movement in 3rd byte.
SWPB R3 Move result into LSB.
*Update mouse X position.
MOV @MSXPOS,R9 Get stored mouse X position.
CI R2,128 Is X movement left (-ve) or right (+ve)?
JLE UPDTX1 Jump if to the right.
AI R2,>FF00 Movement is to the left. Change to two's
* complement word.
A R2,R9 Subtract (add two's complement) movement from
* mouse X position.
JGT UPDTX2 If position now > 0, it's valid.
JEQ UPDTX2 If position now 0, it's valid.
CLR R9 Result is < 0, so reset position to 0.
JMP UPDTX2
UPDTX1 A R2,R9 Add movement to X position.
CI R9,2*255 If X position > 2*255 then set to 2*255.
JLE UPDTX2
LI R9,2*255
UPDTX2 MOV R9,@MSXPOS Store new mouse X position.
*Update mouse Y position.
MOV @MSYPOS,R9 Get stored mouse Y position.
CI R3,128 Is Y movement up (-ve) or down (+ve)?
JLE UPDTY1 Jump if down.
AI R3,>FF00 Movement is up. Change to two's complement word.
A R3,R9 Subtract (add two's complement) movement from
* mouse Y position.
JGT UPDTY2 If position now > 0, it's valid.
JEQ UPDTY2 If position now 0, it's valid.
CLR R9 Result is < 0, so reset position to 0.
JMP UPDTY2
UPDTY1 A R3,R9 Add movement to Y position.
CI R9,2*191 If Y position > 2*191 then set to 2*191.
JLE UPDTY2
LI R9,2*191
UPDTY2 MOV R9,@MSYPOS Store new mouse Y position.
**
*Move mouse pointer sprite.
**
*First byte in SAT is vertical position, second byte is horizontal position.
MOVMS MOV R11,@SAVR11 Save return address.
LI R8,SATBA1+>4000 Reference SAT. Add >4000 for VDP write
* operations.
BL @SENDAD Send VDP address.
MOV @MSYPOS,R2 Get stored mouse Y position (which is at twice
* screen resolution).
DECT R2 Top row of the screen has value -1, so adjust.
SLA R2,7 Move to MSB and divide by 2 to convert to screen
* resolution.
MOVB R2,*R7 Write the Y mouse position.
MOV @MSXPOS,R2 Get stored mouse X position (which is at twice
* screen resolution).
SLA R2,7 Move to MSB and divide by 2 to convert to screen
* resolution.
MOVB R2,*R7 Write the X mouse position.
MOV @SAVR11,R11 Restore return address.
B *R11 Return.
***************************************************
*Loop until mouse clicked on 'HERE' on bottom line.
***************************************************
WAITHR MOV R11,@SAVR12 Save return address.
WAHR01 BL @UPDTMS Update mouse position.
MOV @MSBTTN,R1
COC @H6000,R1 Check for left mouse button pressed.
JNE WAHR01 Left button not pressed, jump.
MOV @MSYPOS,R9 Get mouse Y position.
SRL R9,4 Divide by 2, then by 8 to convert from pixels
* to lines.
CI R9,23 Mouse on bottom line of screen?
JNE WAHR01 No, jump.
MOV @MSXPOS,R9 Get mouse X position.
SRL R9,4 Divide by 2, then by 8 to convert from pixels
* to characters.
CI R9,11 Mouse over the correct characters?
JL WAHR01 No, jump.
CI R9,14
JH WAHR01 No, jump.
MOV @SAVR12,R11 Yes, restore return address.
B *R11 Return.
**************************
*Workspace, text and data.
**************************
MYWS BSS 32 Workspace.
TXT1 TEXT ' STUART''S TI-99/4A MOUSE DEMO '
TEXT ' ----------------------------'
TXT1L DATA $-TXT1
TXT2 TEXT ' MOUSE DRAWING PROGRAM '
TEXT ' (OPTION NOT IMPLEMENTED) '
TEXT ' (OPTION NOT IMPLEMENTED) '
TEXT ' (OPTION NOT IMPLEMENTED) '
TXT2L DATA $-TXT2
TXT3 TEXT ' SKETCH PROGRAM INSTRUCTIONS '
TEXT ' ---------------------------'
TXT3L DATA $-TXT3
TXT4 TEXT 'USE THE MOUSE TO MOVE THE '
TEXT 'POINTER AROUND THE SCREEN. HOLD '
TEXT 'DOWN THE LEFT MOUSE BUTTON TO '
TEXT 'DRAW AS YOU GO. CLICK THE RIGHT '
TEXT 'MOUSE BUTTON TO CHANGE THE PEN '
TEXT 'COLOUR. '
TEXT ' '
TEXT 'CLICK BOTH MOUSE BUTTONS '
TEXT 'TOGETHER TO RETURN TO THE MENU.'
TXT4L DATA $-TXT4
TXT5 TEXT '*** THIS MENU OPTION IS NOT *** '
TEXT '*** IMPLEMENTED ***'
TXT5L DATA $-TXT5
TXT6 TEXT 'CLICK '
BYTE 97,98,99,98 'HERE' using video inverse characters.
TEXT ' TO CONTINUE'
TXT6L DATA $-TXT6
EVEN
SAVR11 DATA 0 Saved return address.
SAVR12 DATA 0 Second saved return address.
MSXPOS DATA 0 Mouse X position in LSB.
MSYPOS DATA 0 Mouse Y position in LSB.
MSBTTN DATA 0 Mouse buttons pressed.
MSCOL BYTE 0 Mouse pointer colour.
B00 BYTE 0
B16 BYTE 16
H10 BYTE >10
H20 BYTE >20
H5000 DATA >5000
H6000 DATA >6000
H7000 DATA >7000
*Mouse pointer sprite data.
MPTSPG BYTE >F8,>F0,>F0,>D0,>88,>04,>02,>01 Arrow pattern.
MPTSAT BYTE 192/2-1,256/2,>00,>0F Initial position middle of screen, colour
* white.
*Menu selection pointer character data.
MSPDAT BYTE >10,>18,>1C,>1E,>1E,>1C,>18,>10
*'HER' in inverse video characters data.
BYTE >00,>BB,>BB,>BB,>83,>BB,>BB,>BB
BYTE >00,>83,>BF,>BF,>87,>BF,>BF,>83
BYTE >00,>87,>BB,>BB,>87,>AF,>B7,>BB
*Pixel bit mask table.
*Pixel------- 0 1 2 3 4 5 6 7
MASKTB DATA >8040,>2010,>0804,>0201
END