The package can be downloaded from my website at http://www.nouspikel.com/ti99/bug99_1.zip
Bug99 started its career as a remote debugger, it allows to control the TI-99/4A through a parallel cable. A small routine in the TI-99/4A memory communicates with the PC and allows for memory access, program execution, etc. Breakpoints are implemented by replacing a given instruction with an XOP. Unfortunately, the increasing level of paranoia packed in Windows made my task difficult: XP and Vista do not allow a program to control the parallel port directly. In addition, my new laptop does not even have a parallel port. And since I moved to the UK, I don't even have a TI-99/4A to play with.
So Bug99 acquired an internal emulator, and thus became a bifunctional program. The idea is that you debug your TI-99/4A program on your PC, using the emulator. When it works, you transfer it to the TI-99/4A and debug it further (if needed) with the remote function.
Be avare that Bug99 is not a very good emulator for playing games (for one thing, it has no sound). It is mainly intended as a debugger for assembly and GPL programers. It should be used in conjuction with a package allowing you to write assembly or GPL programs on your PC. You could use Wordpad, but I recommend Source Edit as a text editor, and I have configured it to do syntax coloring in assembly and GPL. From within Source Edit, you can launch an external assembler. Eventually, I am planning to write a procedural assembly myself, but so far I am using the excellent package by Jean-Francois Rossel. It contains an assembler, a GPL assembler and the corresponding linkers. Once linked, the program can be loaded into Bug99 with the File --> Load command and debugging can begin.
The main drive behind this program was to help me write DSRs for the exotic hardware that I designed, such as the IDE and USB cards. But you will find that Bug99 also emulates a number of more classical devices. I haven't bothered with emulating a floppy drive, though, since I always work from the Horizon Ramdisk instead.
In my opinion, a good debugger should offer the following functions:
The Registers window
The GPL window
The Disassembly window
The Breakpoints window
The Memory window
The Watch window
The Trace window
The Hitmap window
The Screen window
The Bus window
The File menu
The Edit menu
The View menu
The Execute menu
The GPL menu
The Trace menu
The Setup menu
The Window menu
The Help menu
General CRU interface
VDP
TMS9901
Console memory and modifications
Widget and cartridges
32K memory expansion
AMS and derivatives
IDE card
USB-SM card
_USB device controller
RS232 card
Horizon ramdisk
p-code card
German GramKarte
P-Gram card (not implemented)
HSGPL card (not implemented)
Load memory
Dump memory
Disassemble memory
Trace setup
Trace filter
CRU map
Options
Monitor setup
Breakpoint setup
Watch variable setup
Memory find
Memory copy
Memory compare
Legal disclaimer. Read this first.
The contents of this webpage are for educative purposes only. I'm not a professional programmer, and therefore I cannot guarantee that the program described in here will function properly. In fact, it probably won't. It may even cause damage to your computer. And quite possibly set it on fire and burn your house to ashes, sending toxic fumes in the whole neighbourhood. Actually, it may even kill you. So if you know where your interest is, don't install it! Don't even think of it. Furthermore, be aware that using some of the third-party software included with this package (including but not limited to ROM and GROM images) may constitute a copyright violation, an infringement on FCC regulations, a federal crime or whatever it is called in the country you live in. You have been warned! By reading this page further and/or installing the software described herein, you agree on taking whole legal and moral responsability for any disapointment, loss of data, damage, accident, catastrophe, or apocalypse that this package may directly or indirectly cause or favor. And if you were thinking of suing me, forget it. I may have an MD but I'm only a scientist: I don't have any money.
The program detailed below is copyrighted by me, Thierry
Nouspikel, till the end of time or 50 years after my death, whichever occurs
first. I grant you the right (but not the exclusive rights) to use it,
and even to distribute it, as long as you understand that I take no responsability
for it. If you distribute it, be sure to include my copyright and a link
to the present webpage. Thanks.
To use the remote control function, you will need to build a parallel cable according to the instructions found here. You will then need to transfer a small control routine onto your TI-99/4A. Alternatively, you can type it in: the source file is included in the main zip file under the name Bug99.s. Obviously, you will need a parallel port on your PC and an RS232 card on your TI-99/4A. Because Windows won't let a program access the parallel port directly, you also need a third party DLL, called inpout32.dll, which I have included within the package. As far as I know, it is an open source freeware and it's virus-free, but I cannot wouch for this. To enable remote connections, go to "Setup-->Options-->Remote" and select either the remote TI-99/4A or an external emulator. The internal RS232 simulation is selected by default (so that a faulty inpout32.dll won't prevent the Bug99 from starting) but it's not very useful for you..
To launch the program, double-click on the Bug99.exe file (you may want to create a shortcut for it). If the program crashes on startup, the most likely reason is a corrupted workspace file. Remove the file "workspace.wrk" from the application folder and try again.
The first thing you should do now is to configure your system using "Setup-->CRU map", "Setup-->Options", and some of the tabs in "Setup-->Devices" if so desired. Then save your workspace with "File-->Save workspace". I recommend that you create a dedicated folder for each program that you wishe to debug and save your workspace in it. This way you can have a customized set of options, info windows, etc for each project.
At this point, you will probably want to open a few information windows. Use File-->New (or the corresponding button) to open a Screen window, a Disassembly window, and a Register window. Later on, you may want to add a Memory window and a Watch window. You can arrange them, resize them, and customize some of them to you liking, then save your workspace. Next time you debug this program, just reload the workspace and you'll get the same set of windows at the proper place, with the same options.
What you do next depends on your goals: are you debugging your own program, reverse-engineering a third-party program, or just trying to get a better understanding of the TI-99/4A? To debug your own program, you will generally load it into the simulation with "File-->Load memory" and begin from there. But you may also load a "floppy disk" into your Ramdisk, using "Setup-->Device" and one of the [Import] button on the "Ramdisk" tab. Then start the emulation with "Execute-->Run" and load a program into memory by typing commands on your emulated TI-99/4A. While in Run mode the PC keyboard is assumed to represent the TI-99/4A keyboard. The <Alt> key is the Fctn key, and <Ctrl> is the Ctrl key. In some cases, you can use PC-specific keys, such as <Backspace> or the arrow keys, to emulate key combinations on the TI-99/4A (e.g. Alt+S for the left arrow), but the key combination works as well when typed on the PC keyboard. To stop the emulation and start debugging, just press the <Esc> key.
If you need a cartridge, you can load one into the "Widget" device, using "Setup-->Device" and clicking one (or two) of the [Change] buttons on the "Widget" tab. I am not providing any cartridge dump with this package, always for copyright reasons. If you have your own cartridges, you can easily transfer them from your TI-99/4A to a PC file with the "File-->Dump memory" command.
To walk through the debugged program, use the "Execute" menu, or the "GPL" menu if you are debuggin GPL. See the description of these menus for more details.
You can also set breakpoints, and trace execution. See the corresponding
chapters below.
Similarly, when you enter a number, your input is assumed to be hexadecimal, whether or not you include a leading > sign. If you wish to enter a decimal number, append a decimal point to it (but no zero). You can also prefix a number with - (minus) to enter a negative number, or ~ (tildle) to obtain a bitwise inversion (i.e. ~0000 is FFFF). The value you entered is checked as soon as the cursor leaves the edited field (i.e. when you click or tab out of it). If it does not correspond to a valid number, the old value is restored. There are a few exceptions, in which you are allowed to enter an empty field, or a text string like "Current", but these will be mentioned when applicable.
Bug99 uses two diferent philosophies to handle user input. With information windows, any changes you make must be confirmed by clicking a dedicated button, generally called [Set], to commit the changes to memory. By contrast, when controlling a device from the Setup-->Device property sheet, any change you make become effective immediately.
Have fun!
This menu regroups most of the commands that allow you to control
the execution of 9900 assembly language programs.
Step
Executes one instruction, then updates all the information windows.
Breakpoints are ignored by this command.
On the remote system, this command is implemented by copying the current instruction inside the small routine that enslaves the TI-99/4A to the PC. This way, once the instruction is executed, control is immediately returned to the PC. Obviously, this will not work with instructions that change the return point. The following instructions are thus emulated: all jumps, B, BL, BLWP, RTWP, XOP, X, LIMI, and illegal opcodes. Note that interrupts are always disabled in this mode.
Walk
Continuous execution, updating the information windows after each instruction.
Execution will stop if a breakpoint fires, if you press the <Esc> key,
or click the left mouse button inside a window. Note that GPL breakpoints
are ignored when executing assembly. The command also introduces a delay
between instructions, so you can follow the information presented. The
speed is preset at 3 instructions per second, but you can change this in
Setup --> Options-->Execute.
With the remote system, Walk is implemented by just repetedly calling Step. If you enable both the remote TI-99/4A and the simulation, execution will stop as soon as one of these systems hits a breakpoint (or when you hit <Esc>). Since execution is coordinated, both systems should be in the same state, (assuming they started in the same state, of course). However, execution on the remote system happens before the simulation, so if a PC breakpoint is hit in the simulation you will find that the remote system is one instruction ahead.
Run
Continuous execution at maximum speed. The TI-99/4A sceeen image is
the only window updated during execution, and then again only 10 times
per second. All information windows will be updated when execution stops
(either because a breakpoint fired, because you hit <Esc> or clicked
inside the application). If you check the appropriate box in Setup -->
Options, execution will slow down to match the speed of a real TI-99/4A
(assuming your PC is fast enough to allow it). For maximum execution speed,
uncheck that box.
With the remote system, this command does not call Step. Instead it returns full control to the TI-99/4A. The PC can only regain control if a breakpoint is hit, or if you manually re-enter the enslavement routine. Note that this is the only mode in which interrupts are active on the remote system.
If you enable both the remote TI-99/4A and the simulation, control will only be returned to you once both systems hit a breakpoint. If you stop the simulation by hitting <Esc> the program keeps running on the remote system. The only way to regain control on the remote system if your program fails to hit a breakpoint is to reset the console and reload the enslavement routine (and your program)..
Jog
This is a combination of the walk and run commands. It runs continuousely,
and updates all the information windows after a given number of instructions.
This number can be set in the Setup --> Options menu.
With the remote system, this command repeatedly calls Step. Since remote execution takes much longer than emulation, the number of instructions between window refreshes should be set at a much lower value than that used in simulation-only mode. If both modes are on, the value for the remote system will be used, since it is the limiting step. Just like with Walk, execution proceeds in parallel in the two systems, so they should stop after the same number of instructions.
Skip
Jumps over the current instruction without executing it.
Reset
Allows to simulate a reset. There are several possible types of reset:
Reset > Soft is the software reset, equivalent to BLWP @>0000. This is the only type of reset that works with a remotely-controlled TI-99/4A.
Reset > Console emulates a hardware reset, such as what happens when powering up the console, inserting a cartridge, or pressing the reset button on a Widget. The hardware signal resets several processors in the console and causes a software reset. It is also passed to the PE-Box, typically resetting all CRU bits to '0'. By contrast, RAM in PE-box card is not affected.
Reset > PE-box is equivalent to turning the PE-Box off, then on. It will wipe out RAM in PE-box cards (which is not emulated), but will not affect the console, and thus won't produce a software reset.
Reset > Both combines the above. It is equivalent to a full system shut off and power up.
Interrupt
Allows to trigger interrupts and control the interrupt service routine
(ISR).
The top three items report the status of the three types of interrupt
to the TMS9901 processor: VPD interrupts, interrupts for peripheral cards,
and interrupts from the timer internal to the TMS9901. By clicking these
items you can set or remove a given interrupt request. If any of the three
is set, the ISR will be entered next time interrupts are allowed (i.e.
after a LIMI 2).
With a remote system, you can view the current status of these interrupts,
but you cannot modify it.
Interrupt > Call ISR is used to enter the ISR immediately, regardless of the value of the interrupt mask, or of any pending interrupts. Since interrupts are hard-wired at level 1 on the TI-99/4A, this command is equivalent to BLWP @>0004. Normally, this lands you at >0900, with a workspace at >83C0 (which the ISR immediately changes to >83E0).
Interrupt > Exit ISR is used to exit the interrupt service routine before it is finished, and resume execution where it was when the interrupt occured. It works by loading the workspace found at address >0004 (normally >83C0) and performing a RTWP.
Interrupt > Trigger NMI emulates the non-maskable interrupt caused by bringing the LOAD* line down. This requires a special hardware device, such as the WiPo mouse, or Jeff Brown's interrupt mod. The command performs a BLWP @>FFFC. To return from the NMI, just do a RTWP.
JMP
Only works when the current instruction is a jump: it forces the jump
to be taken, whether the requested condition is true or not. To do the
opposite (i.e. not to take the jump), use Skip.
B *R11
Emulates a B *R11, also known as RT. This allows you to return from
a subroutine called with BL without waiting for it to finish.
RTWP
Allows you to abort and return from a subroutine called with RTWP.
Branch...
Calls a dialog box asking where you want to go, and how. In the dialog
you can select the type of branching operation: B @ is a simple branch,
BL @ saves the return point in R11, BLWP @ performs a context switch (i.e.
changes the workspace and saves return parameters in the new R13-R15).
You enter the address you want to branch to in the nearby edit box, in
hexadecima format. In the case of a BLWP, this will be the address containing
the branch vectors, i.e. new workspace and new address.
Optionally, you can specify in which device the memory address you
want to branch to is located, and in which page if the device supports
multiple pages.
Breakpoints
This toggle item allows you to globally disregard breakpoints. When
the item is checked, breakpoints work normally, when it is unchecked breakpoints
are ignored: they won't fire and they won't be traced. The only exception
is when using "Run" on the remote system: these breakpoints fire no matter
what (but that's for "Run" only, "Jog" and "Walk" allow you to disregard
remote breakpoints).
This menu regroups commands that allow you to debug GPL programs.
At the moment, this only works with the emulator, not with a remote TI-99/4A.
Step, Walk, Jog, Run, and Skip work pretty much like they do with assembly. Refer to the Execute menu for details. The main difference is that GPL breakpoints are active with these commands, whereas PC breakpoints are ignored.
Note that, after executing a GPL instruction, the PC will always be >0078 (in standard mode) or >04E6 (in FMT mode). If the current value of PC is different from that one, pressing Step will only trigger execution until PC reaches one of these two values, which may not correspond to a complete GPL instruction. For instance, if a memory breakpoint fired during a GPL instruction, selecting Step will complete execution of this instruction, rather than moving to the next one.
RTNC
Emulates a Return with Condition GPL command. The return address is
fetched from the GPL subroutine stack, and the GPL status bits are not
cleared.
Branch
If the current instruction is a BR, BS, or B, the command takes the
branch regardless of the value of the Eq status bit. To do the opposite
(i.e. not to take the branch), use Skip.
FMT
Controls the Format sub-interpreter of the GPL interpreter. As you
know, a given byte can correspond to two commands in GPL: one in normal
mode, and one in format mode. The normal opcode FMT enters format
mode, which mostly comprises screen access command. The format opcode FEND
is used to leave format mode. An additional complication is that the byte
encoding FEND (>FB) is also understood as a LOOP instruction in format
mode. The emulator keeps track of the number of loops opened (with format
RPTB commands) and, upon meeting a >FB byte, decides whether it must close
a loop or (if there are no more loops) exit format mode.
FMT > On emulates a FMT opcode, thereby entering the FMT subinterpreter.
FMT > Off emulates a FEND opcode and leaves FMT mode regardless
of the number of RPTB loops currently opened.
FMT > Loop++ increments the loop counter. It means that one
more >FB byte will be interpreted as a LOOP command rather than a FEND.
FMT > Loop-- decrement the loop counter.
Tracing is an important tool when debugging. Rather than stepping
though your program waiting for it to crash, you just launch it in Run
mode with tracing enabled. When it crashes, you can inspect the trace log
to find out what happened. Assuming you saved enough information, you can
even backtrack your program upto the point when the crash occured.
Bug99 handles two distinct trace logs, one is intended to trace program execution, the other to trace any manual changes you make (e.g. patching your program). This being said, you are free to choose what you want to save in each log. The logs are saved as .txt files (Trace.txt and Patch.txt), so you can open them in an external viewer (although not while Bug99 is running). But it is probably more convenient for you to use the trace viewing window; it offers events coloring, filtering, etc.
Execution
This is a toggle item. When ticked, tracing is on for program execution.
Assuming you have used Trace --> Setup to select events to trace,
these will be saved into the log file called "Trace.txt".
Patches
This toggles tracing into the Patches.txt file. Both log files can
then be viewed within a Trace Window.
Hits
This toggles counting of memory access and CRU operations by the simulation.
The counters are internal to Bug99, but their values can be displayed with
the Hitmap Window.
Setup
Lets you select what you want to trace, and how much detail to include.
Setup > Execution... controls what will be saved in the Trace.txt
file
Setup > Patches... controls what will be saved in the Patches.txt
file
Both items call up a dialog box that lets you decide which events should
be traced and how much information should be included in the log file.
See below for details.
Wipe
Empties a given log file.
Wipe > Execution clears the Trace.txt file.
Wipe > Patches clears the Patches.txt file.
Wipe > Hits clears the internal hit counters for all memory
types (and CRU).
The next items are only active when viewing a trace log with the trace window. To do so, open a trace window from the file menu, with File --> New. You will be presented with a dialog box that lets you decide which of the traced events you wish to display (obviously, events that were not traced cannot be displayed, but the dialog doesn't know what was traced). You can also set the color of each type of event: just click on the colored button and pick a new color. Do not forget to indicate whether you want to display the Execution log, or the Patch log: this is done with the drop list at the top of the dialog..
Upon clicking [OK], the selected trace log will be displayed. You can affect the events being displayed with the trace menu.
Reload
Calls the filter/color setup dialog again. When you click [OK], the
display is cleared and the log file is re-loaded according to your specifications.
Filter
Call the filter setup dialog, but only applies to the currently selected
section. This way, you can display previously hidden details, or on the
contrary hide useless information from a subsection of the log.
Expand
Display all the information between the current item (the one the cursor
is on) and the next visible item. If several items are selected, all details
within the selection and upto the next visible item will be displayed.
Collapse
Within the selected section, revert to the initial settings of the
filter, as specified when opening the window or reloading the log. You
will find that this option works better if you selected only a few event
types unpon loading. This way, you can reveal the other with Expand and
hide them with Collapse.
For more information, see the chapter on the Trace
window, below.
The various events that can be traced are arranged in sets of two lines, each comprising several checkboxes. The first line lets you decide whether or not an event should be trace. The second line governs the amount of detail to be included with the traced event. A minimum amount of info is always saved (generally the address), but you can add more. For instance, when tracing memory access, only the memory address is logged. But you have the option to include the PC of the instruction that caused that memory access, or the contents of the memory address (and its previous content, in the case of a memory write).
You can trace the following events::
System
This cascading menu item gives you the choice between two systems to
debug from: the internal simulation of a TI-99/4A, or a real TI-99/4A controlled
via a parallel cable. Tick the one you wish to use.
You may tick both, in which case you will be writing to both systems,
but reading from the remote TI-99/4A only. This may be useful, because
the simulation lets you see more things than a real system.
If you untick both, you will not be writing to any device, but you're
still reading from the simulation (since a no-read no-write state didn't
appear very useful to me).
Some of the information windows (Memory, Disassembly and to some extent Watch window) allow you to bypass this setting and to access a system other than the one selected here.
CRU map
This item call a dialog box in which you enter the CRU addresses of
the devices you wish to use in the simulation, and of those that are present
in your remotely controlled system. On the right, you should enter the
CRU address of the bits controlling any modification to the console, such
as overclocking, suppresion of wait states, adding EEPROMs on top of the
console ROMs, or triggering non-maskable interrupts together with regular
ones.
Devices
This item calls a modeless dialog box, one that you can leave open
while working with the rest of the application. It contains a property
sheet with several pages that control the various devices that are emulated
or remotely controlled. See below for details.
Options
This item call a modal dialog box (i.e. one that you must close to
continue working), containing a property sheet with several pages of options,
which are detailed below.
This dialog box lets you customize various options. These are grouped
by topics, and can be selected by clicking the appropriate pane. Unless
otherwise stated, changes only become active when the dialog is dismissed
with [OK]. Clicking [Cancel] instead discards any changes.
Use R for register: decides whether workspace registers are listed
as R0 through R15 or as 0 through 15. The TI assembly allows both, but
no R is the default.
Use NOP. Replace JMP to the next instruction with NOP (no operation).
Use RT. Replace B *R11 with RT (return).
Use $-relative jumps. Decides whether the destination of jump
instructions should appear as an address (e.g. JMP >A008) or as
a PC-relative offset (e.g. JMP $+6, where $ represents the current
instruction).
Prefix addresses with A. Decides whether addresses in left column
and in instructions should appear as numbers (e.g. >2000 B @>3000)
or as labels (e.g. A2000 B @A3000). The "A" prefix comes handy
when saving the listing to a text file, as it can be assembled immediately,
with all addresses understood as labels.
Use extended GPL. Decides whether non-standard GPL opcodes will
be listed as BYTE instruction, or as XGPL instructions (the later may imply
decoding extra bytes for arguments).
Always use G@ notation. Decides whether arguments representing
a GROM address should be listed as G@address or as @address. This does
not apply to the MOVE instruction that always uses G@ for GROM addresses
since cpu addresses are also possible with MOVE.
Prefix addresses with G. Decides whether addresses in left column
and in instructions should appear as numbers (e.g. >6000 BR G@>7000)
or as labels (e.g. G6000 B G@G7000). The "G" prefix allows addresses
to be interpreted as labels by a GPL assembler.
The number of instructions per second while in Walk mode.
The number of instructions executed before the information windows
are refreshed in Jog mode. There can be different value for the simulation
and the remote system, as Jog mode is much slower on the remote system.
Whether Run mode should be as fast as possible, or reined in to match
the speed of a real TI-99/4A (taking clock modifications into account,
if any). This assumes that your PC is fast enough to actually achieve real
speed...
Display statistics when done. Decides whether you want to see
a message box when leaving Walk, Jog or Run mode. The message box states
the cause for interruption (breakpoint or manual), the number of instructions
executed, the time it took, and the time it would have taken on a TI-99/4A.
It must be dismissed by clicking [OK] which can be a pain, hence the option
to suppress it.
Report conflicts on Read. Causes a message box to pop up when
a memory read operation, or a CRU input operation is answered by two devices.
The message box must be dismissed by clicking [OK].
Report conflicts on Write. Same as above for memory writes and
CRU output. This is not really a conflict since it's often ok for more
than one device to latch the same data, but you may want to know about
it...
Load recently used files. This is the list of files appearing
in the dialog boxes used with File --> Load memory and File --> Dump memory.
Load options. Load the list of options, i.e. the contents of
the present dialog box.
Load windows position. Closes any existing information window
and open new ones according to the information found in the workspace file.
Only the position and the appearance of a window is loaded, not its contents
(as this is not part of the workspace file). However, if a window has been
saved on a file, the file name is saved in the workspace. When opening
a new worskpace, the program will try to locate that file and load it into
the window. This does not happen if a window was not saved on a file, or
if the file does not have a standard extension (such as .cmt, .rgs, .bps,
etc).
Load device setup. Loads all device characteristics listed in
the Setup --> Device dialog.
Load trace setup. Loads the events to trace and list, as provided
in the dialog boxes called by Trace-->Setup-->Execution and Trace-->Setup-->Patches.
Does not load the file size, nor the on/off tracing toggles.
Save memory on exit. This refers to simulated TI-99/4A memory,
not to the remote system. Your choices are to save nothing, to save EEPROMs
and non-volatile RAMs, to save ROMs, EEPROMs and nvRAMs, or to save all
memory types. The memory type is taken from the Setup-->Devices dialog.
A given memory will only be saved if it was modified since the program
started, or since the last time you saved it (by clicking the [Change]
button in the Setup-->Device dialog).
Save workspace on exit. Your options are "Always", "Never" and
"Ask me". The later will call a message box when you close the program
and ask whether you want to save the current workspace or not.
The same pane also lets you decide the location of the two folders used
by the application.
The simulation folder is the one containing all the ROM and
EEPROM files used by the application. Normally, you will not change it.
The working folder should contain the program you are debugging
and its specific workspace. This is the default folder used by File-->Save,
File-->Open, File-->Load memory, File-->Dump memory, File-->Disassemble
memory, File-->Open workspace, and File-->Save workspace.
Locked. Decides whether the working folder should change if
you select a different folder in any of the File operations listed above.
If you check the "locked" box, the only way to change the working folder
is from the Setup-->Options dialog: just click the [Change] button and
pick a new folder.
Contact. Bug99 offers you three options for remote debugging:
1) To communicate with a real TI-99/4A connected to the PC parallel
port via a PIO cable. Note that this relies on the existence of a third-party
DLL, inpout32.dll, which is included in the Bug99.zip package.
2) To communicate with a third-party emulator which simulates the TI-99/4A.
Of course, this is only possible if the author of said emulator has made
provisions to support Bug99.
3) To communicate with Bug99 internal simulation, via the simulated
RS232 card. This is not very useful from your point of view, since you
can do much more by accessing the simulation directly (with Setup-->System-->Simulation).
I implemented this option for debugging purposes, and I figured I may as
well make it available. Since this is the only option that does not rely
on third-party programs, I made it the default upon power-up (so a faulty
third party program won't prevent Bug99 from booting). If you want to perform
remote debugging, you must change this field to one of the other options
every time you launch Bug99.
PC port used. You can choose between 4 parallel ports, LPT1 through
LPT4, assuming your PC has that many. This is only relevant when connecting
to a real TI-99/4A.
Handshake in. Selects the PC parallel port pin connected to
the "Handshake in" line of the TI-99/4A PIO port. This is determined when
you build your parallel cable, the default is "Init" if you followed the
instructions on my website.
Handshake out. Selects the PC parallel port pin connected to
the "Handshake out" line of the PIO port. The default is "Ack*".
Timeout value. Determines how long the PC should wait for an
answer from the TI-99/4A. Zero means "wait forever".
[Test] This button attempts to talk to the TI-99/4A and annouces
the results. To do so, it must first accept any change you may have introduced
in the above fields (thus, you cannot cancel these changes by pressing
[Cancel] any longer). For this to work properly, the "enslavement"
routine should be running on the TI-99/4A, otherwise you will get an "Operation
failed" message. The same error message may also be caused by you picking
wrong values for Handshake in or Handshake out. If the test succeeds, the
current position of the hook routine and its workspace will be obtained
from the TI-99/4A and displayed below.
XOP used for breakpoints. Remote breakpoints are implemented
by replacing the target instruction with a XOP instruction. In principle,
there are 15 XOP instructions available to the TMS9000, but in practice
the console ROMs only contain meaningful vectors for XOP1 and XOP2 (and
then again, some consoles do not implement XOP2). Bug99 will read the proper
vector from the console ROM and use them even if they make no sense, but
for all practical purposes, you should use XOP1.
Hook routine location. Determines the location of the short
9900 assembly routine that handles communications and enslaves the TI-99/4A
to the PC. This is preset when loading it on the TI-99/4A, but the routine
can run anywhere. If you change the address in this dialog box and click
[Move it], the routine will be moved to the specified location in the TI-99/4A.
Hook routine workspace. Specifies the location of the workspace
registers used by the enslavement routine. This is determined when assembling
and loading the routine on the TI-99/4A, but you can change it with this
dialog and the new workspace will be used as soon as you click [Move it].
[Move it] This button uses the new values you entered in the
above two fields and adjusts the position and/or the workspace of the enslavement
routine accordingly. This commits any change you may have done to the above
3 fields, which means you cannot discard them by dismissing the dialog
with [Cancel] (but you can retype the old values).
Save
Save as...
With these commands you can save the contents of an information window.
They bring up a dialog box in which you can select the file name and extension.
Most windows can be saved to a text file, which you can then open in
a word processor (or with Wordpad) to edit, format or print it. The exceptions
are the Screen window which is saved as a bitmap file, and the Trace window
which is saved in RTF format.
Some windows can also be saved in an internal format that can then be re-loaded with the File-->Open command. See individual window descriptions for details.
Open
This command is only available for windows that can be saved
in an internal format. It allows you to re-load the contents of a previously
saved window. In some cases (e.g. the Register window), this contents is
just displayed and will only be commited to memory when you press [Set].
See individual window descriptions for details.
Close
This closes a given information window.
Open Workspace...
This lets you pick a new workspace, among previously saved ones. You
can select which type of workspace information should be loaded by selecting
the "Workspace" tab in the dialog box called by Setup-->Options.
When the program starts, it automatically loads the default workspace
from a file called "workspace.wrk" located in the simulation folder. I
suggest that you save a workspace file in the folder of the application
you are debugging and load it when you start working on that program again.
This way you can save customize your workspace differently for each program
you are debugging (e.g. do you want GPL or assembly, etc). While you are
at it, you should also use the "Save" pane of Setup-->Option to change
the working folder (which is the simulation folder by default) to the one
the program you are debugging is in.
Save Workspace as...
This lets you save the current workspace on a .wrk file, so you can
reload it later. All types of workspace information are saved on file every
time, but you can ignore some when loading (see above).
Your current workspace may be saved automatically when exiting Bug99,
depending on what you selected in the "Save" pane of the dialog box called
by Setup-->Options.
Load memory...
This is used to load a file into the TI-99/4A memory, whether on the
remote system or in the simulation. The command brings up a dialog box
that lets you pick up a file and set the loading parameters. Nothing is
loaded until you click the [Load] button. See below
for details.
Dump memory...
This commmand allows you to save chunks of the TI-99/4A memory (remote
or simulated) into a file. The command brings up a dialog box that lets
you select the memory to be saved, the file name, the file format, and
optional additional parameters (depending on the format). See below
for details.
Disassemble memory...
This command lets you disassemble a large chunk of memory (assembly
or GPL), saving the listing to a text file. The command brings up a dedicated
dialog box that lets you pick the file name and set various disassembly
options. See below for details.
Print...
Print preview
Print setup...
Printing is not implemented in the current version. If you wish to
print something, save it to a text file and print the file from a text
editor.
Most recently used files
This the files that were recently used with the File-->Save and File-->Open
command, i.e. corresponding to information windows. The list does not comprise
memory files used by File-->Dump, File-->Load, and File-->Disassemble.
Exit
Leaves the program. Modified memories may be saved on file before exiting,
depending on the options you selected with Setup-->Options-->Save. Similarly,
your workspace may be saved automatically or not.
Filename: The file to be loaded (if any). To pick a new file, just click the [Browse] button. Alternatively, to reload a previously loaded file, select it from the drop list. The file extension determines its format, and may cause some of the other fields to be filled in automatically.
Format: The format of the file to be used. This is filled automatically
if you pick a file with a known extension (.bin, .ea5, .gk or .fb6). Otherwise,
you'll have to select it manually.
Currently available formats are:
Flags: First word of the header (not applicable for .bin files).
Next file: This lets you decide what to do if the continuation
flag indicates that another file should follow the current one. Your choices
are: load = go on with the next file, stop = load this file only, ask =
fill the dialog with the parameters of the next file but don't load it
yet (i.e. you'll need to click [Load] after each file).
Address: The address where to load the contents of the file.
Place into PC: For assembly language only, place the address
at which the first file is loaded into the program counter (PC). This will
allow you to start execution right away. Be aware that a real EA5 loaded
also prepares VDP memory prior to running a file, so you may have to simulate
this by pre-loading another file into the VDP memory.
Size: The number of bytes to load.
Click [Cancel] to abort, or [Load] to proceed. If there
are more files to load, and you set the "Next file" field to "Ask", you
will need to click [Load] again for each file.
This dialog box is called up by the File-->Dump command and is used
to save a portion of the TI-99/4A memory into a file, either from the remote
machine or from the simulation. It contains the following fields:
Filename: The file to be loaded. To pick a new file, just click the [Browse] button. Alternatively, to overwrite a previously saved file, select it from the drop list. The file extension determines its format, and may cause some of the other fields to be filled in automatically (provided the file already exists).
Format: The format of the file to be used. This is filled automatically if you pick a file with a known extension (.bin, .ea5, .gk or .fb6). Otherwise, you'll have to select it manually. Formats are the same as in the File Load dialog.
Memory: The type of memory to load into, cpu, GROM/GRAM, or VDP
memory.
Device: The device to load into (optional).
Page: For paged devices, the page to use. For GROM/GRAM memory,
the GROM base to use.
Flags: First word of the header (not applicable for .bin files).
Leave this field blank if you want the program to coin the flags automatically.
More files to come: This is only used if you left the "Flags"
field blank. Tick the box if you are planning to add more files, untick
it for the last file. (If you are planning to save one big chunk of memory
into contiguous files, you may use "Split after" instead).
Address: The memory address where to start saving from.
Size: The number of bytes to save.
Spit after: The maximum number of bytes that can fit into one
file. If Size is greater than this number, additional file(s) will be created.
In the latter case, the program overrides the "Flags" and "More files to
come" settings and forces the presence of the continuation flag.
Click [Cancel] to abort, or [Load] to proceed. If there
are more files to load, and you set the Next file field to "Ask", you will
need to click [Load] again for each file.
Filename. The file into which to write the disassembly. This should be a text file, but it does not necessarily need to have a .txt extension; it could be .asm, .gpl, .s or anything you use for your source files. To pick a new file, click the [Browse] button. Alternatively, you can select a previously used file from the drop list.
Append if exists. If this box is checked and the file you selected
already exists, anything you disassemble will be appended to the end of
the file. If the box is not checked, an existing file will be erased before
use.
The next series of fields let you select the memory that you wish to
disassemble.
Memory type could be cpu, grom or VDP, no matter what you assembly
language you are using. This way, you can disassemble 9900 assembly language
embeded within a GROM (and meant to be copied to cpu memory for execution),
GPL stored in VDP memory, etc.
From is the address where to start from.
To is the address where to stop, an instruction beginning at
this address will not be included in the listing.
You can also select the system (remote TI-99/4A or simulation), and
optionally select a specific device and a page number (or a GROM base,
if you selected GROM memory).
Format: This drop list lets you select the language you want to disassemble into. You can choose between 9900 assembly and GPL. You can also elect to disassemble a chunk of memory as a list of DATA statements, BYTE statements, or TEXT statements. Note that in the case of TEXT, any non-printable character (i.e. ascii code lower than 32 or higher than 127) will be replaced with character 127.
Start with Fmt on. This checkbox only appears if you selected the GPL format. It lets you decide whether the Fmt sub-interpreter is on or off at the start of the disassembly. Subsequently, the subinterpreter will be automatically turned on by FMT statements and off by FEND statements.
Words per line, bytes per line, characters per line: This field
only appears if you selected DATA, BYTE, or TEXT as the format. It lets
you specify how many words of data will follow a DATA statement before
a new line is issued. Similarly, you can select the number of data bytes
following a BYTE statement, or the number of characters to be included
in a TEXT string.
The options you selected for the Disassembly windows in Setup-->Options-->Disassembly also apply to this bulk disassembly. In addition, you have a few more specifc options that are only relevant to disassembling on file:
Include comments. If you have entered comments via a Disassembly window, you have the option to include them in the disassembled listing by checking this box. Comments are not included with DATA, BYTE or TEXT formats.
Include hex values. This is only relevant to assembly and GPL format. It causes the listing to include a list of the hexadecimal words/bytes that make up an instruction. These values will appear after the instruction, but before comments.
Use names of watched addresses. If you have any named variable or addresses listed in a Watched window, with the "Use in disassembly" property selected, checking this box will cause them to be used in the disassembled listing in place of their hexadecimal values.
Generate names for labels. This causes the program to go over
your disassembled section twice. On the first pass, it makes a note of
any address the program is refering to and creates a dummy name for it.
Cpu memory addresses are named Axxxx where xxxx is the hexadecimal value
of the address. Similarly, GROM addresses are named Gxxxx, and VDP addresses
Vxxxx. On the second pass, when the listing is generated, these temporary
labels are used any time the corresponding address appears in the listing.
They also appear as labels in the left margin if an instruction happens
to begin at such an address. Note that if you select both this option and
the "watched addresses" option, the name of a watched variable is prefered
over a temporary one.
.bin A simple binary dump of a chunk of memory
.ea5 A binary dump of cpu memory, preceeded with a 6-byte
header compatible with the Editor/Assembler cartridge, option 5.
.gk A binary dump of GROM or cpu memory, preceeded
with a 6-byte header compatible with the Gram Kracker.
.fb6 A binary dump of any type of memory, preceeded with
a 6-byte "ea5" header, followed with a varible-size trailer containing
extra info. See this page for details.
.dsk A sector dump (in numerical order) from a floppy disk.
Does not contain track info (i.e. not compatible with PC99 format).
.hdd Ditto, but meant for hard drives. Sector size is
generally 512 bytes, and there can be many more sectors, but basically,
it's the same format as .dsk.
.smc A sector dump of a SmartMedia card, in numerical
order, preceeded with a 16-byte header. Sectors can be 256 or 512 bytes,
and each sector is followed with 8 or 16 bytes of special
info.
.rgs An internal format allowing to save and reload the
contents of the Registers window.
.cmt A text file allowing to save and reload the
comments entered manually in Disassembly windows.
.bps An internal format allowing to save a list of breakpoints
and to reload it into a Breakpoints window.
.wtc An internal format allowing to save a list of watched
variables and to reload it into a Watch window.
.gpr An internal format allowing to save and reload the
contents of the GPL registers window.
.rtf A standard rich-text format file allowing to save
the contents of a Trace window while preserving colors and formatting.
.hit A text file allowing to save a list of non-zero
hits from the Hitmap window and reload it later. The list can also be viewed
in a Trace window, if the extension is changed to .txt
.txt A standard PC text file. Pretty much any window
can be saved into a text file but, since the trace log files have a .txt
extension, .txt files are loaded into a Trace window by File-->Open.
.bmp A standard PC bitmap file produced when saving the
Screen window (in which case it contains a 16-color palette) or the Hitmap
window (in which case it's a 4-million colors bitmap).
Cut
Currently only available for a Trace window. Deletes the selected text
and places it in the Clipboard.
Copy
Currently only available for a Trace window. Places the selected text
in the Clipboard.
Paste
Currently only available for a Trace window. Inserts the content of
the Clipboard at the current cursor location, possible replacing selected
text.
Memory copy
Only available for a Memory window. Calls a dialog box that allows
you to copy a portion of memory onto another. See below
for details.
Memory compare
Only available for a Memory window. Calls a dialog box that allows
you to compare two section of memory and point at any mismatch. See below
for details.
Compare again
Looks for the next mismatch.
Find
Only available for a Memory window. Calls a dialog box that allows
you to specify a string of bytes or text to look for within a given portion
of memory. See below for details.
Find again
Finds the next occurence of the target string.
Replace
Only available after the target string was found. Allows you to replace
it with the substitution you specified when setting up the search.
Replace all
Replaces all occurences of the target string with the substitution
string. Only available after the target string was found once.
Count
Only available for a Trace window. Displays the number of events of
each type within the selected portion text.
Status bar
Toggles the status bar on/off.
Monitor
Only available for a Screen window, this menu cascades down to three
sub-items.
Monitor > Color. Loads the predefined colors to emulate a color
monitor.
Monitor > B & W. Loads a prededined greyscale to emulate
a black-and-white TV, or a monochrome monitor.
Monitor > Custom... Calls a dialog box (described later),
that lets you customize the Screen view by defining the colors, adding
borders, or changing the aspect ratio.
Zoom
Only available for a Screen window. Sets the magnification at which
you wish to display the emulated TI-99/4A screen. Valid values are 1:4,
1:2, 1:1, 2:1, 4:1 and 8:1. You can also select "Smaller" which decreases
magnification by 1.4 , or "larger" which increase it by 1.4. Finally, "Fit
window" adjusts magnification so that the whole screen will fit inside
the current window. Note that, if the window aspect ratio is not 192/256,
the largest dimension will be decreased to fit the screen image.
Lines
This is used by most information windows (except for the Screen window
and the Registers window), to set the number of lines to be displayed.
See the description of the individual windows for details.
Tile
Arranges and resizes windows so they do not overlap.
Arrange icons
Aligns the icons for minimized windows.
Resize
Adjust the size of a window. This may have different effects, depending
on the type of window. For more details, see the description of this command
in the description of each individual window.
List of open windows
Click on one of these to make it the active and topmost window. Convenient
if it is hidden under many others.
About Bug99...
Displays version number and copyrights.
You can display or hide the toolbar with the View --> Toolbar command. When it is displayed, the following commands are accessible via a button on the toolbar:
File --> New
File --> Open
File --> Save
File --> Load memory
File --> Dump memory
Edit --> Cut
Edit --> Copy
Edit --> Paste
Edit --> Find next
Edit --> Replace
Execute --> Run
Execute --> Jog
Execute --> Walk
Execute --> Step
Execute --> Skip
Execute --> JMP
Execute --> RT
Execute --> RTWP
GPL --> Run
GPL --> Jog
GPL --> Walk
GPL --> Step
GPL --> Skip
GPL --> RTNC
Execute --> Breakpoints (toggle button)
Trace --> Execution (toggle button)
Setup --> Devices
File --> Print (inactive)
Help --> About Bug99
Help --> What's this (inactive)
This small window is especially useful when debugging assembly programs.
It displays the microprocessor registers, toghether with the workspace.
The information comes from either the emulator or the remote TI-99/4A,
depending on which one you selected with Setup-->System.
ST Microprocessor status register. It's further broken down if the following bits: L logically greater than (unsigned), A greater than (signed) E equal, C carry, O overflow, P odd parity, X XOP in progress, IM interrupt mask. The later is a 4-bit field and accepts values from 0 to >F. However, since interrupt level is hardwired as 1 in the TI-99/4A console, the only relevant values are zero and non-zero.
PC Program counter, i.e. cpu memory location of the next assembly instruction to be executed.
WS Workspace pointer, i.e. cpu memory location of the 16 registers, R0-R15, as far as the microprocessor is concerned.
Grom is the current Grom/Gram address, as found in the internal counter of console GROM 0. This is the address of the next byte to be read from Grom (or Gram) memory.
Base is the value of the base address (e.g the one used to read bytes) for the current Grom port, which is found in >83FA. Normally it is in the range >9800-983C.
Workspace: address of the workspace that you wish to display. This does not necessary have to be the same as WS (e.g. if you want a glimpse at a different workspace). You can enter your own address, or pick one from the drop-box: >83E0 is the GPL workspace, >83C0 the initial interrupt workspace, >20BA the workspace provided by the Editor/Assembler cartridge. If you set this field to "= WS", it will automatically follow the value of the workspace pointer field (WS).
R0 through R15 display the contents of the 16 workspace registers, based on the cpu address found in the "workspace" field.
[Read] The content of this window is refreshed automatically upon assembly execution, but you also have the option of trigerring a manual refresh, by clicking the [Read] button. For instance, you can use it to view the workspace contents after you changed the value of the "Workspace" field. Note that [Read] will cancel any change that hasn't yet been saved with [Set], and revert all fields (except the "Workspace" field) to their current value in the emulation or the remote TI-99/4A.
[Set] You can modify the contents of any of the above fields,
but your changes will only be commited to memory when you clicking one
of the [Set] buttons. The upper one will save everyting except registers,
the lower one will save the registers only.
File --> Open allows you to set the contents of the register window from data previously saved with File-->Save. This happens automatically when you open a file with an .rgs extension: a new register window is open, with all fields preset according to the file contents. You will need to press [Set] to commit these values to memory, which gives you a chance to edit them first.
Window --> Resize returns the window to its default size.
GPL Current GROM/GRAM address. When running the GPL interpreter, this corresponds to the next GPL instruction to be executed.
Base Address used by the GPL interpreter to access GROM memory (normally >9800, but this can change). This address is stored into cpu memory word >83FA.
ST GPL status byte. A breakdown of the only 5 relevant bits is provided. L logically greater than (unsigned), A greater than (signed) E equal, C carry, O overflow.
FMT As you may known, the GPL interpreter comprises a sub-interpreter used for screen access. It is called FMT (for Format) and gives a different meaning to the opcodes used in GPL. Thus, it is very important to know whether you are in FMT mode or in standard GPL mode. FMT mode is entered via the FMT instruction and left via the FEND instruction. You can also toggle FMT mode manually, by clicking the checkbox. Note that this is only possible if the current GPL (or FMT) instruction has completed. If that's not the case, the FMT box is grayed out. Select GPL-->Step to complete the current instruction and this should enable the box.
Next to the FMT box is a numeric field that reflects the number of currently nested RPTB loops in FMT mode. This is necessary because the opcode to close a loop is the same as the one to leave FMT mode (>FB). The advantage is that you cannot possibly exit FMT mode with a loop left open, but it forces us to keep track of how many loops have been open. This info is stored in cpu memory, at word >83F2 while in FMT mode. You can enter a new value, or alter the current one with the spin buttons. This field has no meaning in standard GPL mode, and is thus disabled.
Row Current screen row. This is the position where a character written to @>837D will be echoed on screen in standard GPL mode. In FMT mode, this is where writing will continue for instructions like HCHAR, HTEX, etc.
Col Current screen column. See above.
Sub Subroutine stack pointer. This must be a scratch-pad address, i.e. comprised between >8300 and >83FF. You can enter a new value, or increment/decrement the current one with the spin buttons.
The subroutine stack is displayed directly below the pointer. It is always 32 bytes in length and aligned on a 32-byte boundary. A < mark points to the current location of the pointer. When a new return address is pushed on the stack (by the CALL instruction), the pointer is incremented first, then data is written to the stack. In other words, the pointer points at the last valid address that was placed on the stack, and will be used as a return point by the RTN and RTNC instruction. If the stack is empty, the pointer will contain an address inferior to the stack base, and you won't see any < mark in the stack list. You can type new values inside the stack, but they will not be commited to memory until you press [Set].
Data Data stack pointer, and associated data stack. These work exactly like the subroutine stack and pointer, except they respond to different GPL instructions (PUSH) and are used for different (and somewhat vague) purposes.
[Read] This button refreshes the contents of the GPL window. It is not terribly useful, as refreshing is performed automatically when a change is detected. However, you may use it to cancel changes that you entered in one of the editable fields, rather than committing them to memory by pressing [Set]
[Set] If you entered new values in any of the above fields, or
in one of the stacks, they are confined to the GPL window. Memory will
only be altered when you press [Set], at which point all fields in the
window are copied to memory.
File --> Open allows you to set the contents of the register window from data previously saved with File-->Save. This happens automatically when you open a file with an .gpr extension: a new GPL register window is open, with all fields preset according to the file contents. You will need to press [Set] to commit these values to memory, which gives you a chance to edit them first.
View --> Lines allow you to change the number of lines displayed in the stack lists. The minimum is 1, the maximum is 16 (since stacks are 16 words at max).
Window --> Resize adjusts the size of the window so that it matches
that of the stack lists.
This window allows you to display and alter the contents of the
three memory types: cpu, grom/gram, and vdp memory. The leftmost part of
the window displays addresses, the middle part shown memory contents in
hexadecimal notation, and the rightmost part shows it in text mode.
In the leftmost edit field, select the desired system you wish to address: either the simulation or the remote TI-99/4A. When the window is first created, it comes up with the current system selected by Setup-->System, but you can change this.
The next box selects the memory type: cpu, GROM/GRAM or VDP memory.
In the next box, enter the desired address. If you enter "Current" (or simply "Cur") the window will automatically follow the current address. For cpu memory, this is the value found in the program counter PC, i.e. the location of the next instruction. For GROM the current address is that of the next byte to be read, and is obtained from the device that answers the current base. For VDP memory, the current address is read from the VDP, and corresponds to the next byte to be read from VDP memory.
You can also use the drop-list to select a preset address. For VDP memory, you have the option to select "Screen" to show the address of the screen image table, "ColTab" for the color table, "CharPat" for the character pattern table, "Sprites" for the sprite attributes list, and "SpPat" for the sprite pattern table. You can also type these names (or at least the first 3 characters) directly into the address box. In any case, you will have to click out of the box to translate the name into an address, and you need to click [=] for the window to display this address.
Device lets you specify a given memory device. If you select "Current", the device accessed will be the one that currently answers at the selected address. If no device answers, the memory window will be empty with the simulation and filled with >FF bytes (most likely) with the remote TI-99/4A. If you select a given device, its memory will be displayed (assuming the address is in the correct range), even if the device is not currently active. This is a good way to quickly check the DSR memory of a simulated card without having to turn it on first.
Page is only meaningful with devices that have multiple cpu memory pages. You can use it to speficy which page you want to edit. If the page number is invalid, the memory window will be empty. If you enter "Current" or "Cur" to access the page that is currently selected on this device. Be aware that the remote system cannot restore the original page number afterwards...
Base replaces Page for GROM memory. It lets you select the GROM base through which memory should be accessed. You can use the drop box to select a base among the 16 supported by the console ROMs, or you can enter your own value. If you enter "Current" or "Cur", the base value will be taken from cpu address >83FA (which is R13 in the GPL workspace). If you enter "Any", the default base for the current device will be used (or >9800 on the remote TI-99/4A).
Text controls the display in the righmost part of the window. You can use the standard ascii code, or the biased version used by TI-Basic, in wich an offset of >60 is added to each character before display. In any case, only characters in the range 32-127 will be displayed, the others are represented with a bullet.
You can navigate in memory using the five small buttons:
[^^] moves one page up
[^] moves one line up (16 bytes)
[=] refreshes the display. You must click this button after changing the address (or device, or page). This is also useful to cancel changes in edit mode, or to return to the current address (if the address field says "Current") after you paged away from it. This is the default button, which means that pressing <return> while the Memory window has the focus is the same as clicking this button.
[v] moves one line down (16 bytes)
[vv] moves one page down
[Set] You can make changes in either the hedecimal or the text
field. When entering hexadecimal bytes, you may use spaces to separate
bytes but don't have to. When entering text, you can only type characters
with an ascii code in the range 32-127. When you click out of the edited
field, your changes will be reformated. If you are satisfied with the result,
click [Set] to commit them to memory. Otherwise, you can always click
[=] to cancel your changes.
File --> Save
Allows you to save the contents of the memory window to a text file.
If you want to save memory so as to reload it later, use File-->Dump
File --> Open
This menu item does not offer any file extension to load data into
a memory window. Instead, you should use File-->Load to load data directly
into memory.
Edit --> Find
Allows you to search for a text string, or an array of bytes in the
memory of your choice. If the target is found, the memory window will be
set to display it. The command first calls a dialog box in which you select
the parameters of the search:
In the Source box, you select the type of memory and the addresses where to start and end the search (the end address is not included in the search).
You can also select the device to be searched, or just leave it as "Current".
For devices that have paged cpu memory, you can set the number of the first and last pages to be searched (the last page is included in the search). If the number of the last page is smaller than the first page, the seearch will go backwards, from highest to lowest page (you cannot do this with memory addresses, though). When searching GROM/GRAM, the page fields let you enter the first and last GROM bases to search.
In the "Find" field, you enter the string that you would like to find. The drop box on the right lets you indicate whether you have entered a series of hexadecimal bytes, an ascii string, or a text string in biased ascii. Text strings are case sensitive. By contrast, hexadecimal bytes are not: A-F and a-f are accepted. You may separate bytes with any character you like, or just stick them together (e.g. 123456AC9). If you enter an uneven number of digits, the last digit will encode the least significant nibble of the last byte (>09 in the example above).
In the "Substitute" field, you can specify another string that you would like to be substituted for the target one (Don't worry, nothing will happen just yet.) Here also, a drop box lets you specify the type of input you used. The format is the same as for the target string.
Click [Find] to start the search. If the target is found, the memory window will display it and several more options become available in the Edit menu.
Edit --> Find again
Keep searching for the target string, starting with the address and
page at which it was last found
Edit --> Replace
Replaces the target string with the substitute one. The whole substitute
string will be written to memory, even if its size is not the same as that
of the target string. This means that you can replace "Cow" with "Bovine":
you will just overwrite the 3 characters following each occurence of "Cow".
Edit --> Replace all
Replaces all occurences of the target string with the substitute string,
within the memory range that you selected.
Edit --> Memory copy
This command allows you to copy a portion of memory into another location.
It first calls a dialog box, which lets you define the source and destination
for the copy operation.
The Source box is identical to the one used by the Find command (see above). It lets you select the memory type, the start and end address to be copied (the end address is not copied), an optional device, and the first and last memory page (or GROM base) to be copied (the last page is copied).
Below is a "Destination" box, that lets you decide where to copy the memory. You can enter a memory type different from that of the source, if you so wish. You should then specify the address where to begin the copy, the end address is of course determined by the size of the source data. You can select the target device, which does not have to be the same as the source device. For paged devices, you can also select the first page to copy to (or the first base for GROM). The last page is determined by the number of pages specified for the source. Page numbers always increment in the target, even if they decrement in the source, which allows you to copy "backwards".
Click [Copy] to perform the copy operation
Edit --> Memory compare
This command lets you look for differences between two memory locations.
If a mismatch is found, the memory window will be set to display it. The
command calls a dialog box identical to the one used for memory copy.
The Source box lets you specify the first area of memory that you would like compare. The "With" box, does the same for the second area. Note that the end address and end page for the second area are determined by what you selected for the first area.
If no difference is found, the program displays "Exact match". Otherwise, the memory window is set to display the mismatch in the source memory.
Edit --> Compare again
You can use this command to keep comparing memory, starting from the
location of the last detected mismatch.
View --> Lines
Lets you define how many lines you would like to display inside the
window. Valid values are 1 to 48. In addition, the command refreshes the
display and adjusts the size of the window..
Window --> Resize
Adjusts the size of the window so as to fit the number of lines and
the minimal width that displays all fields.
In the leftmost edit field, select the system you want to access: either the simulation or the remote-controlled TI-99/4A.
In the second edit field you select the language to use, which automatically selects the memory type. Valid choices are:
The Device field lets you specify a device to disassemble from. You can select it by name, or by CRU address. The device will be accessed, even if it would normally not answer to a memory request. You can also use "Current" or "cur" to select the device that's answering at the selected address. If none answers, the listing will be blank with the simulation and full of >FF bytes with the remote system.
Page is used with cpu memory devices that offer the option of displaying multiple memory pages at a given address. Enter the required page number (in hexadecimal notation), if it is invalid nothing will be displayed. Alternatively, you could use "Current" or "cur" to access the currently active page. Be aware that the remote system cannot restore the original page number afterwards.
Base replaces page for GROM devices. It lets you specify the base address of the GROM port to read from. You use the list box to select one of the 16 ports supported by the console ROMs, or enter your own value. If you enter "Current" or "cur", the base value will be read from cpu byte >83FA. If you enter "Any", the default base for the current device will be used (or >9800 on the remote TI-99/4A).
You can scroll the disassembly window using the five small buttons:
[^^] moves 16 bytes up for GPL, 16 words up for 9900 assembly.
[^] moves 1 byte up for GPL, 1 word up for 9900 assembly.
[=] refreshes the display, using the current address. You must click this button after changing the address, device, page or base. It can also be used to return to the current address after paging away from it. This is the default button, so hiting <return> while the Disassembly window as the focus is the same as clicking this button.
[v] scrolls down by one instruction
[vv] scrolls down one page, i.e. begins disassembly at the instruction
immediately following the last one in the current window.
A 5-column list control is used to display the disassembled program.
The first column in the listing is used to display breakpoint. A star * indicates an active breakpoint, whereas an empty circle o indicates an inactive breakpoint.
The second column contains the address the instruction. The current instruction is marked with >> for the simulation and -> for the remote system. The simulation can check that the device and page/base match your specifications (or were set as "current", but the remote system cannot. So if you are disassembling memory from a device that's not currently on, you will never see the >> mark, but you may see the -> one.
The third column contains a disassembly of the memory contents. The Setup --> Option dialog box lets you specify a few options regarding the format. If the memory address contains a value that does not correspond to any opcode, it will be displayed as a DATA statement. In the case of GPL, unimplemented opcodes can be listed as XG-0 through XG-G, and XG-$ (where XG stands for extended GPL), depending on your options.
The fourth column displays the memory contents in hexadecimal notation. This can be useful if you have DATA or BYTE statements within a program, which is common practive both in assembly and GPL.
The fifth column gives you the option of entering comments. These comments can be saved on a .cmt file with the File-->Save command, and then reloaded with the File-->Open comment. Comments are "global", i.e. they are not restricted to a given Disassebly window, but rather linked to a given address. If the device is set at "Current" the comment will apply to any device. If a specific device is selected when a comment is entered, this comment will only be displayed when this device is selected or is the current one. The same apply for device pages and GROM bases: when this field is set as "current", new comments apply to any page/base. When the field specifies a given page or base, any new comment will be specific to that page/base (note that specific pages are only valid with a specific device).
Any execution or GPL command will move the >> mark within the window. If execution is transfered outside the displayed area, the >> mark of course disappears. If you have set the address to "Current", the window will move to keep displaying the current instruction. There are two possibilities here: if execution moves to an address close to the last address currently displayed, the window will scroll down by half a window and display the current instruction (I find this easier to follow than scrolling a whole window). If execution is transfered further away, the current instruction is displayed at the top of the window.
You can alter the contents of the disassembly window, i.e. patch the
program, by clicking in a line. Due to a Windows quirck, the leftmost column
must be visible for this to work (no horizontal scroll). To patch a program,
enter a new instruction in the third column, or new numeric values in column
4. To enter new comments (or delete existing ones) edit column 5. To cancel
editing, click out of the edited field. To confirm changes, either press
<return> or click the [Set] button. The difference is that <return>
moves to the next line, while [Set] leaves edit mode.
Set/Clear BP
Sets a "PC" or "GPL" breakpoint at this address. If a breakpoint already
exists, the command removes it.
Activate/Inactivate breakpoint
Obviously only works of there is a breakpoint at the current address.
If the breakpoint is active the commands inactivates it, and conversely.
Jump here
Sets the PC (or the GROM address, in case of GPL) to the instruction
you clicked on. It thus becomes the next instruction to be executed.
Run to here
Sets a temporary breakpoint at the address you selected, then enters
Run mode. The breapoint is removed when execution stops (for whatever reason).
In most cases, it will be the temporary breakpoint that fires, and the
pointed instruction will become the next to be executed. However it may
not be the case if the program meets another breakpoint, or goes on a stray
and has to be stopped manually. Note that globally disabling breakpoints
with the Execute-->Breakpoints command will not disable this temporary
breakpoint, so you can use it to make sure execution won't stop till it
reaches the desired address.
Peek argument 1
Only works with opcodes that have at least one argument. It calls the
dialog box that lets you view and edit a watched variable, optionally creating
a Watch window in the process (if none was opened). This gives you a chance
to check the current value of the argument, and possibly to edit it. You
have two options to dismiss the dialog: click [Watch] to add the argument's
address to the list of watched variables (in the first Watch window that
was open). Alternatively, click [Done] to dismiss the dialog without modifying
the Watch window.
Peek argument 2
Does the same thing for the second argument of opcodes that have more
than one argument.
Peer argument 3
Only works with the GPL opcode MOVE, since it's the only one that can
have 3 arguments.
File --> Open
Lets you reload a set of comments previously saved to a .cmt file.
These will be merged with existing comments, if any. In case a new comment
shares its address with an existing one, it will replace the old one.
View --> Lines
Lets you define how many lines you would like to display inside the
list control. Valid values are 1 to 1000. In addition, the command changes
the size of the control so as to fit inside the current window.
Window --> Resize
Adjusts the size of the window so as to fit the list control.
This window displays a simulation of the TI-99/4A screen. This is
the only window that is updated in Run mode.
File --> Save
Saves the sceen image to a bitmap file of your choice. This comes handy
to take screen snapshots. The colour palette is saved together with the
image, but the zoom factor, the aspect ratio and the borders are not (these
are saved with the window, as part of your workspace).
File --> Open
Lets you view a previously saved bitmap file. The file must be in the
proper format, i.e. include a 16-colour palette (not all bitmap files do).
The new image will disapear from the screen window as soon as you perform
an operation that causes VDP memory to be updated, but the colour palette
remains attached to the newly opened window. This is thus a great way to
save and reload custom-designed palettes.
View --> Zoom
Controls the size of the image displayed in the window. The size of
the window itself is adjusted to encompass the entire image, if this is
not acceptable to you, you can resize the window by hand. Scoll bars will
appear automatically if the window is too small to display the entire screen
image. This menu item cascades down to the following options:
Zoom > 1:1 No zoom, i.e. one pixel on the PC corresponds to
1 pixel the TI-99/4A.
Zoom > 2:1 Two-fold magnification. This is the default when
opening a new screen window.
Zoom > 4:1, 8:1 Further magnification.
Zoom > 1:2, 1:4, 1:8 Respectively cause a 2-fold, 4-fold, and
8-fold reduction in size.
Zoom > Larger increases magnification by 40%
Zoom > Smaller reduces the magnification by 40%
Zoom > Fit window adjusts magnification so that the image will
fit the current size of the window. If the aspect ratio of the window does
not match that of the TI-99/4A screen, the image will be adjusted according
to the smallest dimension of the window, then the window is resized so
that its larger dimension fits the screen image.
View --> Monitor
Controls the way the screen image is displayed inside the Screen window.
This menu item cascades down to three sub-items:
Monitor > Colour. Sets the colour palette to emulate a colour
monitor.
Monitor > B & W. Sets the colour palette to emulate a black-and-white
TV, or a monochrome monitor.
Monitor > Custom. Calls a dialog box that lets you define your
own colors, add borders and change the aspect ratio (see below).
Window --> Resize
Adjust the size of the window to fit the bimap image at its current
level of magnification.
The dialog displays the current settings for the 15 colors (transparent has no color of itself). A colored button displays a sample, followed with the three color components: Red, Green, and Blue. The next column contains the luminance value, i.e. the amount of brightness we perceive. Since our eyes are most sensitive to green and least sensitive to red, the relative contributions of the three color components are multiplied by different factors to give a decimal number from 0 to 1000. These factors vary a bit according to the exact wavelength of each component, which is hardware dependent. Thus, you have the choice between two formulas: the old-style luminance (Y) which is most useful with old phosphorus monitors, and the modern "luma" (Y') which may reflect modern monitors more accurately.
There are basically three ways to modify the color palette. First, you could click a colored button: this will call Window's color picker, from which you can select a new color. Its components and Y value will be displayed, and the Screen window updated immediately.
Second, you could manually edit color components. Legal values are >00 to >FF. Any change takes effect as soon as you click out of the modified field.
Finally, you could use the controls on the right, which affect all colors
together. Just click the corresponding [-] or [+] buttons to decrease or
increase the chosen property.
Brightness. This increases or decreases the value of all three
components together. Note that, if a component is >FF it cannot be further
increased. Conversely, a component cannot be deceased below zero. This
may result in irreversible changes (i.e. clicking [-] may not reverse a
click on [+]).
Contrast. When you increase contrast, any color with a Y value
above 500 will have its brightness increased, any color with a Y value
below 500 will have its brightness decreased. Decreasing contrast produces
the opposite effect.
Saturation. This allows you to change the color saturation,
i.e. the "intensity"of a color. Increasing saturation will increase the
color component which has the highest value, and decrease the one with
the lowest value. The third component sides with the one it is the closest
with (e.g. if red=20, green=80, blue=90, green will increase with blue).
Decreasing saturation produces the opposite effect and, at the limit, turns
the palette into a scale of grey.
Red hue. Allows you to increase/decrease the amount of red for
all colors.
Green hue. Does the same for green.
Blue hue. Does the same for blue.
At the bottom of the dialog is a frame called "Borders", that let you
add borders to the screen picture. These borders will be displayed in the
screen backgroung color, as specified in the second nibble of VDP register
7. Changes become effective when you leave the modified field.
Note that the maximum value for the the Left and Right borders is >10
(i.e. 16 pixels), whereas the top and bottom borders can have upto 64 pixels
(max value >40).
There is a special case in text mode, since the screen picture is only
240-pixel wide (40 characters of 6 pixels each). If you click the checkbox,
8 pixels in screen color will be added on each side of the picture to bring
it to 256-pixel in width. If you do not click this box, the screen image
will be stretched horizontally so as to occupy the same space as a 256-pixel
wide picture.
Finally, you can change the aspect ratio, i.e. the ratio of height over width. Normally, the TI-99/4A screen is 192 lines by 256 pixels, so the default value of the ratio field is >C0 (i.e. 192). By entering a different value, you can stretch or compress the image in the vertical dimension, an effect that most monitors allow.
When you are satisfied with your changes, click [OK] to make them permanent. Or click [Cancel] to revert to the settings that were in effect when the dialog was called.
Note that all these options (colors, borders, aspect ratio, and zoom
factor) are saved as part of your workspace. In addition, the color palette
is also saved within the bitmap file when you save a Screen window.
In this window, you can specify memory addresses that you'd like
to watch during execution. You can give them a name if you wish, and choose
the type of display that you like. This is one of the cases when it makes
sense to have more than one window the same type: you can have different
watch lists, each in its Watch window.
The following columns are displayed:
Name: an optional name that you can give to the watched variable.
It can serve for you as a reminder, but you can also set it up so it is
used in the Disassembly window, in place of the address it represents.
Address: is the address of the variable you want to watch. You
can use simple addresses (e.g. @>1234) or very complex ones (e.g. V*>0001:1234[>1300]).
See below for details.
Changed: this column is normally empty. If a variable changed
since the last time the Watch window was updated, an exclamation mark !
will appear here.
Value: displays the current value of the watched variable. You
can select the format you want when setting up a new variable: hexadecimal,
decimal, binary, text, etc.
You can edit the Address and the Value field by just clicking in them and entering new data (due to a Window quirk, the Name column shouldn't be scrolled out for this to work). To abort editing, click out of the field. To confirm changes, press <return>. Alternatively, double-click on the Name or Changed column to bring up the same dialog box called by the [New] button, that lets you edit all details of a variable.
[New]
Click on this button to add a new variable to the watch list. You can
also do this by right clicking in several other windows (e.g. the Disassembly
window, which presets the address as one of the arguments of the instruction
you clicked on). In either case, a dialog box appears, which lets you control
what you want to display, and how (see below).
[Delete]
Removes the currently selected variables (one or more) from the watch
list.
File --> Load
When loading a .wtc file, creates a new Watch window and fills it with
the watch list found in the file. Only the first 53 watched addresses will
be loaded.
View --> Lines
Lets you define how many lines you would like to display into the list
control. Valid values are 1 to 53. In addition, the command changes the
width of the control so as to fit inside the current window, then resizes
the window to fit the height of the list control.
Window --> Resize
Adjusts the size of the window so as to fit the list control.
Name
You don't have to give a name to all watched variables, but it may
be useful if you need a remainder of which is which. Also, you have the
option to tick the "Use in disassembly" checkbox, which will cause the
name you entered to be substituted for any occurence of the address in
the disassembly window (both in the address column, and in the disassembled
listing column). You can only do this, however, if the address is a direct
one (e.g. G@>1234). There are no limitations on the length of the name,
but if you plan to include it in the disassembly, it may be wise to stick
with 6-character labels.
Address
Here you specify the address that you'd like to watch. The address
must follow a particular syntax because you can watch all three memory
types, and CRU as well. You can also use various forms of indirect addressing
(i.e. getting the address from another address), and you can select the
target device, page, and base. See below
for a detail explanation of this extended address syntax.
Display type
You can decide in which format the contents of the watched address
should be displayed. Your choices are decimal, hexadecimal, binary, or
text. For text, you can have it in standard ascii, or with the Basic bias
of >60. For numbers, you can decide whether you prefer the byte or the
word notation (i.e. >12,>34 or >1234).
Bytes
Controls the number of bytes to be displayed, in whatever notation.
If you display an uneven number of bytes as words, an implicit >00 byte
is added at the end, i.e. in the least significant byte of the last word.
Value
Display the contents of the address, in the selected format. This field
also offers you the option of altering the contents of said address, by
entering a new value (in the selected format) and pressing [Set]
[Read]
This button refreshes the contents of the Value field. This is useful
in case you changed the address: click on [Read] to see what's in there.
[Set]
This button writes the contents of the Value field back to memory,
at the specified address. It 's useful after you changed the contents of
the Value field, or after you changed the address. In the latter case,
you'll be performing a limited copy operation.
[OK]
Click this button to add the specified address to your list of watched
variables.
[Cancel]
Well, cancels the operation.
Numbers
As usual, numbers are assumed to be hexadecimal, so leading > marks
are optional. To enter a decimal number, append a decimal point at the
end of the number. Numbers can be prefixed with the following signs:
+ (plus) for positive number. This sign is implicit and thus ignored.
- (minus) for negative numbers. -1 is FFFF.
~ (tildle) for bitwise inversion. ~0 is FFFF.
Simple addresses
>1234 is a constant, not an address. It is not very useful in a Watch window since the "Value" column will always contain >1234, but it comes very handy in a conditional expression as it allows you to check if an address contains a given value (e.g. @2000 == 1234).
@>1234 is cpu memory address >1234. Note that the @ sign is required
to make this an address rather than a constant.
V@>1234 is address >1234 in VDP memory. The @ and the > are optional,
but the V is not (obviously).
G@>1234 is address >1234 in Grom/Gram. Again, you need the G but can
dispense with the @>.
U@>1300 is CRU input bit >1300 (Didn't want to use C for CRU, as it
may be confused with CPU).
W@>1300 is CRU output bit >1300. Remember that input and output bits
may have different use with some cards. This only works with the emulator,
as you cannot read an output bit on the real TI-99/4A.
Special addresses
R0 trough R15: represent the contents of the workspace registers, no
matter where your workspace is located. These can be used for indexing
(e.g. *R1) or in complex expressions like those listed below..
PC: the current value of the program counter, i.e. the address of the
next instruction to be executed.
ST: the contents of the TMS9900 status register.
WS: the contents of the TMS9900 workspace register, i.e. the address
of your workspace
GA: the current GROM address.
VR0 through VR7: the contents (byte) of the 8 VDP registers. These
are only available with the simulation, as VDP registers are write-only
on the real TI-99/4A.
VS: the contents of the VDP status register. Reading this does not
clear the interrupt flag with the simulation, but it does with the remote
TI-99/4A (unavoidably).
VA: the current VDP address, i.e. the address of the next byte to be
read/written. Only available with the simulation.
Indirection
There are two ways to specify indirect addresses (i.e. an address that contains the address of the variable you want to watch):
*>1234 is the simplest form of indirect addressing. It means that the
address that you want to watch is to be found at address >1234. For instance,
if address >1234 contains >5678, then you'll be watching @>5678. The advantage
of the indirect notation is that, if the contents of address >1234 changes,
you keep watching what it points at.
V*>1234 is similar: you get the address to watch in VDP memory from
cpu address >1234.
G>*1234 is just like above, except that the watched address is in VDP
memory. In all the above cases, the pointer is located in cpu memory.
*V@>1234 this one goes the other way around: the watched address is
in cpu memory, but the pointer is in VDP memory, at >1234.
V*G>1234 watches the VDP memory address found in Grom address >1234.
**>1234 demonstrates multiple indexing. This get the address to watch
from a cpu memory location, the address of which is found at cpu address
>1234
G*V*@>1234 gets quite complicated: watch the GROM location the address
of which is found in VDP memory, at the address found in cpu address >1234.
And it can get even more complex, if you want!
@>0002(@>1234) is the second form of indexing, which allows for some
basic arithmetic. The address within the parentheses is used as a pointer,
just like with the * notation. However, the number found before the parenthesis
is added to the pointer to find the final address (the contents of the
pointer are not actually modified, the addition is purely internal to Bug99).
For instance, if >1234 contained >2000, this exemple would watch >2002.
@>0000(>1234) is equivalent to *>1234, since nothing is added.
@-2(@>1234) demonstrates that negative numbers are allowed.
@>0001(@>0002(@>1234)) not very useful, as it just adds 3 to the address
found in >1234. This is better written as @>0003(@>1234).
V@>0005(G@>1234) watches the VDP address calculated by adding 5 to
the content of Grom address >1234.
@>0001(*>1234) is another way to perform multiple indexing: the watched
address is calculated by adding 1 to the address found at the address found
in cpu address >1234.
Device and pages
An extended address can be linked to a specific device. With the simulation,
the address can always be accessed, even if the device would normally not
answer. By contrast, if you do not speficy a device, the currently answering
device is used. If none is answering, the Watch window displays "- no data
-". To specify a device, include its name (found in the ID field of its
property page called by Setup-->Devices) or its CRU address within square
brackets, after the address:
@4000[>1300] watches address >4000 in the device that answers at CRU
address >1300.
@4000[IDE] watches address >4000 in the IDE card.
For devices that support multiple pages (or multiple bases in the case
of GROM), you can specify the page/base followed with a colon, ahead of
the address. If you don't, the current page/base will be used (if any).
The only restriction is that page numbers must be smaller than >07FE.
@>0001:>6000 watches address >6000 in memory page 1. Just like addresses,
page numbers are assumed to be hexadecimal, so you can dispense with the
> marks.
G@>9820:>6004 watches Grom address >6000, accessed via grom port >9820.
And of course, you can combine pages with devices. In fact, a page number
only makes sense when attributed to a given device.
@12:A000[1500] watches cpu address >A000 in page 18 (hexadecimal >12)
in the device answering at CRU address >1500.
If you want, you can use indirect addressing to specify a page number,
a GROM base, or a device CRU:
*>1234:5678 watches address >5678 in the page specified in cpu address
>1234.
>5678[*1234] watches address >5678 in a specific device, the CRU of
which is found in cpu address >1234.
V*>1234:**>5678[>0010(>20BA)] I'll let you figure out what this one
is watching...
System
In principle, a Watch window watches all variable in the current system,
as specified with Setup-->System. However, you can force a variable to
be read from a specific system by using one of the following prefixes:
_@1234 The underline represents the parallel cable and means that address
>1234 must be read from the remote TI-99/4A.
$@1234 The dollar sign represents the simulation and forces the Watch
window to display simulated address >1234 even if the current system is
the remote TI-99/4A.
Note that you cannot mix and match: only one of these prefixes is allowed
and it must be the first character in the address.
This only applies to the Watch windows. With breakpoints, the system
is specified by the type of breakpoint (it's always the simulation except
for remote breakpoints).
Summary
Generic format: +T@page:address[cru] where T is the memory type: G, V, U, W, or nothing (for cpu memory). + can be + (plus sign, ignored), - (minus sign, negative number) or ~ (tildle, bitwise inversion).
Indirect adressing: +T@page(index):addr(index)[cru(index)]
where index has the generic format. Nested indirections are allowed.
Index shorthand: *addr = 0(addr) = (addr)
Note that *addr[cru] = (addr[cru]) but *addr [cru] = (addr)[cru]
The space before [cru] makes the difference.
This window is used to display the current breakpoints, or a subset
of these. It is important to understand that the breakpoints exist independently
from the window: closing the window won't remove any breakpoint, and setting
the window so as to display only one type of breakpoint won't inactivate
the other types.
The box in the top part of the window serves as a display filter, so that you can choose what type of breakpoint you wish to view. Most checkboxes correspond to given breakpoint types or properties (e.g. active vs inactive) and will be discussed below. The "Expand size" checkbox is used with memory breakpoints that are covering more than one address: normally they are only displayed at their initial address, but by checking this box you can repeatedly display the breakpoint at each address it reacts to.
The display filter allows you to have several breakpoint windows open, each displaying different breakpoint types. For instance you could have one for assembly-related and one for GPL-related breakpoints.
[Refresh]
Click this button to refresh the display after you modified the filter.
[New]
Creates a new breakpoint, calling a dialog box in which you can set
up the breakpoint type and its properties (see below). You can also create
PC and GPL breakpoints directly from the Disassembly window.
[Act/Inact]
Toggles the currently selected breapoints between active and inactive.
If more than one is selected, the status of the first one is toggled and
applied to all others.
[Remove]
Deletes the currently selected breakpoint(s), no matter how many, no
questions asked...
[Select all]
Selects all the breakpoints currently displayed. Be aware that there
may be more breakpoints, depending on how you set the display filter.
The display contains the following columns:
BP: displays a star * if the breakpoint is active, an empty circle
o if it is inactive.
Type: displays the breakpoint type. See below
for details.
Address: The address at which the breakpoint is hit, or (for
opcodes breakpoints) the opcode values that trigger it.
Count: For counting breakpoint, this columns displays the current
count. Empty for non-counting breakpoints.
Condition: Display the conditional expession that must be satisfied
for the breakpoint to fire. Empty if the breakpoint is unconditional
You can double-click on a breakpoint to edit it. This will call the same dialog box than [New], but with all values preset according to the selected breakpoint. You can alter any field, including the breakpoint type. Just be aware that your changes may render the breakpoint invisible in the current window, according to how you set the display filter.
You can also edit the Count and the Condition field directly from the
list, by just clicking in them (the BP field must be visible for this to
work). Enter a new count or condition and press <return> to confirm,
or click out of the field to abort edition.
File --> Open
When opening a file with a .bp extension, creates all the breakpoints
listed in the file and creates a Breakpoints window to display them (even
if you already have one open). If a breakpoint already exists, you will
be asked if you wish to replace existing breakpoints. You'll only be asked
once and your answer will apply to all further duplicates.
View --> Lines
Allows you to specify the number of lines to display in the list control,
valid values are 1 to 43. The command also adjust the width of the
control to match that of the window, then performs an implicit Window -->
Resize.
Window --> Resize
Adjusts the dimensions of the window to match the list control.
This dialog box appears when you click [New] in the Breakpoints
window, and lets you set up a new breakpoint. It also appears when you
double-click an existing breakpoint, so you can modify its characteristics.
The dialog box contains the following fields:
Type
Determines the type of breakpoint.
For breakpoints reacting to opcodes, you should enter the hexadecimal value of the opcode (and the first byte of the argument for GPL), instead of the address. The easier way to do this is to enter a valid instruction in the "Assembly" field, then click out of it.. This assemble the instruction and place its value in the opcode field.
Device
For some breakpoint types, you can restrict the breakpoint to a specific
device by selecting one from the drop list. You could also pick a CRU address,
and the corresponding device will be selected. If you select "Current"
the device that is currently (i.e. at the time the breakpoint is set) answering
at the specified address will be selected. By selecting "Any" you disable
device specificity.
Page
For paged devices, you can restrict the breakpoint to a given page
by typing in a page number. Be aware that you cannot specify a page
if you selected "any device" (because pages are device-dependent). If you
select "Current" the currently active page (at the time the breakpoint
is set) in the selected device will be selected. You can disable page checking
by specifying "Any" page.
Base
You can do the same with GROM bases for GPL and GROM breakpoints, by
selecting a base from the drop list. In this case, it is possible to select
a specific base even if the device is set as "Any", because various devices
may handle the same base. If you select "Current", the base will take the
current value used by the GPL interpreter, found in word >83FA.
Size
Only applies to memory and CRU breakpoints. If you wish the breakpoint
to cover a group of address (e.g. a string or a buffer area), enter its
size in here. The program will set a memory (or CRU) breakpoint at every
address in the selected range. Leave the size as 0 if you only wish to
break at a single address. Note that if there is another breakpoint withing
the covered range, it will not be replaced with the one you're setting.
And since there can only be one breakpoint by address, this will leave
a gap in the area covered by the new breakpoint.
Assembly
This field only appears for opcode and GPL opcode breakpoints. You
can type an assembly instruction in here (e.g. B *R11) and when you click
out of the field it will be assembled, and the corresponding value (>045B)
placed in the Opcode field. Conversely, when you click out of the Opcode
field, its value is disassembled and the result placed in here. With GPL
opcode, if you assemble a Format opcode, the Fmt box will be checked automatically,
whereas it will be unchecked when you assemble a regular GPL opcode.
Note that, when ignoring the argument type or register value, the ignored bits will be masked with 1s. This will become appearant when the breakpoint is displayed in the Breapoints window: CLR R5, which is encoded as >04C5 with both boxes checked, will appear as >04FF (i.e. CLR *R15+) with both boxes unchecked.
Active
Check this box to activate the breakpoint, uncheck it to inactivate
it. Inactive breakpoints do not halt execution when hit, but they can be
traced. You can also toggle the active/inactive status of a breakpoint
directly from the Breakpoints window, or from the Disassembly window.
Count
Enter a decimal number, negative or positive, in this field to create
a counting breakpoint. Leave this field empty if you do not wish to use
this feature. Every time the breakpoint is hit, the count will increment
by one. Counting breakpoints only fire when the count reaches zero. You
may thus use negative numbers to fire a breakpoint only after a given number
of hits (e.g. enter -5 to fire the fifth time the breakpoint is hit). Alternatively,
enter 0 to count the number of times the breakpoint was hit before execution
was stopped (manually, or by another breakpoint). The Breakpoints window
will display the current count for every counting breakpoints, and you
can include the count in the trace log.
Condition
Here you can enter a conditional expression that must be true for the
breakpoint to fire. Leave this field empty if you want the breakpoint to
fire unconditionally. A conditional expression consists in two variable
addresses (as defined above), separated
with a comparison operator. Both variables will be read, compared, and
the breakpoint will fire if the comparison is true. Either side of the
comparison may also contain an absolute value, so you must use the @ sign
when specifying a cpu address. For insance, R1 == >1234 means "R1 equals
the value >1234" (the > sign is optional), whereas "R1 == @>1234" means
"R1 equals the contents of cpu address >1234".
Valid operators are:
== equal
!= not equal
> greater than
>= greater or equal
< smaller than
<= smaller or equal.
No operator means "different from zero" and in this case there is obviously
only one variable.
By default, all comparisons are unsigned. To perform a signed comparison, include a + or a - sign ahead of the second variable: @>2000 == +R1 (Note that a minus sign negates the contents of the variable, not the address).
By default, all comparison are performed on words (i.e. 16-bit values).
Optionally, you can precede the first expression with an expression in
curly braces that specifies the width of the comparison. Valid values are:
{BYTE} consider only the most significant byte.
{MSB} most significant byte, same as the above.
{LSB} consider only the least significant byte.
{nnnn} where nnnn is an hexadecimal number speficying the bits to be
used in the comparison. For instance >FF00 is the same as MSB and 00FF
is the same as LSB.
Finally, you can use the symbol OLD in place of a variable, on the right side of the operator. Each time a conditional breapoint is hit, the value of the left member of the comparison is saved. OLD can be used to compare the current value to the previous one. In this way, you can restrict a breakpoint to firing upon changes (or lack of) in a given variable. E.g. R1 != OLD prevents the breakpoint from firing if R1 has not changed since the breakpoint was set, or the last time it was hit.
You can combine activation status, count and conditional expression in the same breakpoint.
[OK]
Creates the breakpoint, or modifies it when editing. There can only
be one breakpoint (of a given type) for a given memory address, so you
will get an error message if another breakpoint already exists at this
address. In this case, you will be given the option to replace it. Select
[Yes] to replace the old breakpoint with the new one, [No] to return to
editing the new breakpoint, or [Cancel] to give up creating the new breakpoint.
Note that the window will be empty if there is nothing in the selected
log file! Thus, you should first use the Trace menu to setup trace mode,
turn it on, then perform some of the actions that you want to trace (generally,
executing a program). This will accumulate data into the log files. At
any time, you can display a "snapshot" of the log file within a Trace window.
By snapshot I mean that the Trace window is not updated automatically to
reflect the contents of the log file (this would be too slow), instead
you must select Trace-->Reload to refresh it.
At the top of the setup dialog, you can select which log file you'd like to view: execution or patches. The file Trace.txt is normally used to trace program execution, wherease Patch.txt logs manual changes. This, however, is decided when setting up trace mode and it's entirely up to you to decide which kind of event will be logged into which file. The third option (File) appears when opening a previously saved log file.
Then follows a list of traceable events, each with a checkbox on the left and a colored button on the right. Check the box to display events of that kind in the Trace window (assuming, of course, that you have set up trace mode to log such events, and that some did occur while tracing was on). Tip: Don't check too many boxes, as it would make the "Collapse" and "Expand" functions less useful. By clicking on the colored button, you can change the color in which a given type of event will be listed. The bottom button decides the color of the background. Once you're ready, click [OK] to display the Trace window.
Be aware that the log file may become very large very quickly. In which
case it will take a VERY LONG TIME (upto several minutes) to load the contents
of the file into the Trace window. This is a known problem with Windows
RichEdit control, nothing I can do about it. So just be patient...
NB. The Trace window is actually a RichEdit control, so you could type in it and modify its contents as you like, but be careful as this could make some functions unavailable. For instance, there is a hidden number at the end of each line (printed in background color) that indicates the offset of the current line within the log file. This number is required by functions like "Expand".
The type of event is identified by the beginning of the line:
>nnnn disassembly
PC tracing. nnnn is the current value of PC, the disassembled instruction
is optional.
G>nnnn disassembly
GPL tracing. nnnn is the address of the current GPL instruction, the disassembly
is optional.
@>nnnnw = xxxx -> yyyy PC: pppp GPL: gggg
Tracing of cpu memory access. nnnn is the memory address. A trailing w
indicates a write operation. Optional: xxxx shows the contents of the memory,
yyyy the new value (for writes). pppp show the address of the assembly
instruction that triggered the memory access, gggg the current GPL instruction.
G@>nnnnw = xx -> yy PC: pppp GPL: gggg
Tracing of GROM access. Similar to the above, except that values are listed
as bytes.
V@>nnnnw = xx -> yy PC: pppp GPL: gggg
Tracing of VDP memory access. Same as above.
U@>nnnn = xx (y bits) PC: pppp GPL: gggg
Tracing of CRU read operations. nnnn is the CRU address. Optional: xx shows
the value read, with y being the number of significant bits. PC and GPL
as for memory operations.
W@>nnnn = xx (y bits) PC: pppp GPL: gggg
Ditto, for CRU write operations.
BP tx* nnnnnnnn #:ddd = yyyy
Skipped breakpoints. x is the breakpoint type (as in the breakpoint setup
dialog), a trailing * indicates an active breakpoint. nnnnnnnn is the address
at which the breakpoint fires, including the device or page number in the
most significant word. Optional: ddd is the current value of the counter,
and yyyy shows the current value of the left member of the condition.
Modified address = xxxx -> yyyy Manual
changes to watched variables. address is the address modified, xxxx
the old value, yyyy the new one (the later two are optional).
Modified registers WS= xxxx PC=xxxx ST=xxxx Grom=xxxx Base=xxxx
Manual changes introduced via the Registers window, upper [Set] button.
Modified nnnn = xxxx,xxxx,xxxx...xxxx -> yyyy,yyyy,yyyy....yyyy
Manual changes to the workspace portion of the Registers window. nnnn is
the workspace address, xxxx the values of the 16 registers, yyyy the new
values.
Edit CPU mem: pppp:xxxx-yyyy[cccc] Manual changes to memory,
via the memory window. pppp is the page number (if available), xxxx the
start address, yyyy the end address, cccc the device CRU (if available).
Edit GROM: pppp:xxxx-yyyy[cccc] Ditto for
manual changes to GROM.
Edit VDP mem: pppp:xxxx-yyyy[cccc] Ditto for
manual changes to VDP memory.
Patch >nnnn = xxxx -> yyyy old new
Manual patch to an assembly program, via the disassembly window. nnnn is
the address, xxxx the old value, yyyy the new one. Optional: old
and new disassemblies can be shown.
Patch G>nnnn = xxxx -> yyyy old new
Ditto for manual patch to a GPL program.
Trace --> Patches
Ditto for events selected with Trace-->Setup-->Patches and logged into
the Patch.txt file.
Trace --> Setup --> Execution...
Trace --> Setup --> Patches...
Selects which type of events will be traced into the Trace.txt and
Patch.txt files respectively, and how much extra information should be
included. See above for details.
Trace --> Wipe --> Execution
Trace --> Wipe --> Patches
These commands are used to empty the corresponding log file (Trace.txt
and Patch.txt respectively).
Trace --> Reload...
This reloads a log file into the Trace window, presenting you again
with the filter/colors selection dialog. This can be used to view any changes
that may have occured since the window was created/reloaded (e.g. execution
continues). Remember that the Trace window is static, i.e. it does not
reflect changes to the log file until you reload it. You can also use this
command to cancels any editing, expansion, or filtering, that you may have
done.
Trace --> Filter...
Lets you alter part of the display, by modifying the filter and/or
color selection (except the background color). The process is similar to
that of reloading the window, but only applies to the currently selected
portion of the Trace window. This lets you reveal or hide information in
specific parts of the log file.
Trace --> Expand
Displays all the information available in the log file, between the
current line and the next one. If more than one line is selected in the
Trace window, the information will be displayed for the whole selected
section, upto the first unselected line.
Trace --> Collapse
Reverts the selected section to the filter settings that were chosen
upon loading the file into the Trace window. Note that if you elected to
display everything, the command will not produce any visible change, which
is why it's good to select few event types upon loading a log file.
Trace --> Backtrack
Undoes any write operation that appears within the selected section,
starting from then end up. If nothing is selected, backtracking starts
from the bottom of the window upto the current position of the cursor.
This function lets you "rewind" the simulation upto a given point, from
which you can step forward again. For this to work, you must have traced
write operations for all three types of memory and the CRU, including values
into the listing, and you should also have traced PC and GPL PC.
Trace --> Forward
Does the inverse of the above, i.e. re-executes the events found in
the selected section. This allows you to move the system to a later stage
in the trace file. Just as above, you must have traced all writes and included
values in the listing.
File --> Save
This can be used for two purposes. You can save the current contents
of the Trace window in RTF format, which will include coloring, etc. Or
you can copy the entire log file (Trace.txt or Patches.txt) onto a different
text file, so you can open it again later with File --> Open. Use a .txt
extension to create a reloadable file, any other extension to save the
contents of the window.
File --> Open
When opening a file with a .txt extension, pop up the trace filter
selection dialog, then displays the file into a Trace Window. You will
notice that the combo box in the filter selection dialog announces "File",
followed with the selected file name.
Edit --> Count
This command calls a message box that displays the number of events
of each type that are part of the selected section in the Trace window.
If nothing is selected, only the current line is considered, so you'll
get only one event.
Edit --> Find
Lets you search the Trace window for a given string of text, possibly
restricting it to a given type of event. A dialog box pops up, into which
you can enter the string to search for (e.g. an address). You may leave
the string blank if you merely want to find events of a given type. The
two check boxes affect the text search: case-sensitivity and search
for whole words only. The drop box lets you select a type of event. By
default, it searches any events, but you can restrict the searches to events
of a given type. For instance, you could search for memory accesses at
address >2000, or for the next GPL instruction (by leaving the query string
blank).
If you have selected a number of lines within the Trace window, only the selected lines will be searched. Otherwise, search begins at the line on which the cursor is and continues upto the end of the Trace window. If no match is found, a message box appears to give you the option of searching again, from the top of the file upto the current cursor position. If the search is unsuccessful again, nothing happens. If the target is found, the Trace window scrolls down (or up) to display the line containing the target, which then becomes the current line.
Edit --> Find again
Lets you repeat the previous search, starting from the current position
of the cursor. The current line is not part of the search, which allows
you to find all successive occurences of your query string/event.
Edit --> Copy
Nothing unusual here. The command just copies the selected text into
the clipboard, without altering the contents of the Trace window.
Edit --> Cut
Same as above, but removes the selected text from the Trace window.
Edit --> Paste
Inserts the contents of the clipboard into the Trace window, at the
position of the cursor. If text was selected in the Trace window, it is
replaced with the clipboard's contents.
View --> Lines
Lets you adjust the height of the RichEdit control to display a given
number of lines. Valid values are 1 to 50. The width of the control is
adjusted to match the current width of the window. The command then automatically
resizes the Trace window to match the new height of the control.
Window --> Resize
Resizes the Trace window so as to closely fit the dimensions of the
RichEdit control.
Expand
Collapse
Filter
Backtrack
Forward
Call the same commands as the Trace menu. If you right-click within
a selection, the command applies to the whole selection. If you click outside
a selection, the cursor is first moved there, the selection is canceled
and the command behaves as if nothing was selected.
Peek
Lets you view the contents of the address listed on the line you right-clicked
on. This is achieved by presenting you with the dialog box used by Watched
windows. You can modify the contents of the address with the [Set] button,
add the address to the list of watched variables by clicking [Watch] or
just dismiss the dialog with [Done].
Disassembly
Adjusts the Disassembly window (creating one if necessary) so as to
start at the address found in the line you right-clicked on.
Use the tab control to select the memory you would like to display: cpu, GROM, VDP, or CRU. Note that GROM and VDP access is also represented in the cpu memory tab, at the memory-mapped addresses: >8800, >8C00, >9800, >9802, >9804, etc.
Use the checkboxes to decide which kind of hits you want to display: read operations, write operations, instruction acquisitions, or any combination thereof. An instruction acquisition is defined as a cpu memory read within 3 words of the PC for cpu memory, and as a GROM read within 32 bytes of the current GPL instruction for GROM (the latter only works if you used the GPL menu to execute your program, as the Execute menu does not keep track of GPL instructions).
The drop box on the upper left corner of the bitmap is the zoom factor.
It displays the number of memory bytes displayed in a line. Legal values
range from >100 (i.e. 256 bytes) to >10 (16 bytes). Note that the number
of lines per byte varies accordingly, since a byte is always represented
by a square box. Your choices thus are:
>100 bytes per line, 64K total, each byte is 1x1 pixel.
>80 bytes per line, 16K total, each byte is 2x2 pixels.
>40 bytes per line, 4K total, each byte is 4x4 pixels.
>20 bytes per line, 1K total, each byte is 8x8 pixels.
>10 bytes per line, 256 bytes total, each byte is 16x16 pixels.
If the zoom factor does not allow to display the whole memory, you can use the scroll bar to move up and down the memory. The left axis labels are updated accordingly. Alternatively, you may want to enter the address of the first byte to be displayed in the text box at the top of the left axis.
Under the bitmap are the controls that let you adjust the color scale. The scale comprises 256 colors but, depending on how long you ran the simulation, you may have counts higher or lower than this number. To best visualize memory hits, you should adjust the color scale so that it brackets the range of counts in the displayed memory.
Min: this field and associated slider let you select the minimum count value. Any address with a number of hits equal or lower to this number will be represented with the "zero" color. Legal values are 0 to >FFFE. Most of the time, you will want to leave it as 0, but you may occasionally raise it to hide unfrequent hits.
Max: this field and its associated slider select the maximum count value. Any address with a number of hits equal or greater to this number will be represented with the "saturated" color. Legal values are 1 to >FFFF. For obvious reasons, Max must be greater than Min, so changing one may result in modifying the other. For best color resolution, you should adjust Max to a value slightly higher than the highest number of hits in the display. You can do this automatically, by checking the "Auto" box.
There are several reasons why a given address count may become saturated.
For one thing, the hit counters are 1-word wide. They won't wrap around
to zero, but they won't increase beyond >FFFF. So if an address reports
>FFFF hits, it may actually have been hit much more frequently, there is
just no way to know. Also, you may have set Max to a value lower than the
highest number of hits in the display. In particular, if you are displaying
two or three types of htis together (read, write and instructions), then
the total can add up to 3 times >FFFF (i.e. >2FFFD), but the Max value
still cannot go beyond >FFFF.
So that you can immediately detect such saturation problems, you can
tick the "Saturated = green" box. This will cause the topmost color to
be bright green instread of white. Since green is not part of the regular
"heat scale", saturated values become immediately obvious.
Conversely, there are times when you will want to visualize even a single hit. This may be difficult, since it would be represented in very dark blue, which is not easy to tell from black. The "Zero" slider lets you change the color used to represent zero hits (or any value lower or equal to Min). You can pick any shade of grey, from pitch black to fully white. By selecting a light grey, you can make single hits immediately visible.
All these settings (read/write, scale, zoom and scrool) are specific for each memory type. When you change tabs, the previous values for that type of memory are restored.
On the right of the tab control are the statistics field. By entering an address in the first field, you can see how many reads, writes, and instruction acquisitions (if relevant) this address has accumulated. Rather than entering the address by hand, you may just click into the bitmap: the address of the corresponding byte will be entered automatically.
By entering another value in the "to" field, you can get statistics on a range of memory addresses. The top series of boxes give you the cumulated number of hits in the selected area, the bottom one reports the highest values in each category. Click inside the bitmap while holding the Shift key down to automatically fill in the "to" field.
Note that CRU addresses represent bits, not bytes. Since CRU addresses are always 2 bits apart (the least significant bit of R12 is ignored), every second bit should be zero. I didn't like this stippled appearance, so I decided that odd bits will always match the corresponding even bit. In other word, each bit is represented by a 2x1 pixel box (at lowest zoom). You may notice a similar phenomenon when displaying cpu memory, but here it is due to the fact that the TMS9900 always accesses two bytes at a time, even when using MOVB instructions. Thus, no matter what you do, the number of hits on the odd-numbered byte always equals that of the even byte.
Under the statistics are controls for reseting the counters. Click the
[Wipe] button to reset all counters for all memory types. This is the same
as using the menu item Trace-->Wipe-->Hits.
You can also set up automatic reset. This is useful to give you a "real
time" impression of memory access, rather than a cumulative value. Check
the "auto-wipe" box to enable this feature. You must then select the type
of timeout event from the drop list, and enter the threshold value in the
edit field. You have the option to reset the counters after a given time
(in milliseconds), after a given number of assembly instructions, or after
a given number of hits. In the latter case, only displayed hits are counted;
hits in memory areas that are zoomed out, or not displayed because of the
read/write settings, do not count.
Remember that the display is not refreshed in "Run" mode, and only
refreshed after a given number of instructions in "Jog" mode (specified
in Setup --> Options).
Trace --> Wipe --> Hits
This wipes out the hit counters for all types of access to all memories.
All counts are re-initialized to zero. If you wish to reset one particular
counter without affecting others, right click into the Hitmap Window.
File --> Save
You have the option to save either the bitmap image, or a list of hits.
Select a .bmp extension to save the bitmap, any other extension will produce
a text file with a list of hits for all memory types. Only addresses with
a non-zero number of hits will be included in the list. Use a ".hit" extension
if you wish to reload the list in the Hitmap Window at a later time. If
you use a ".txt" extension, the list can be loaded into a Trace Window.
File --> Open
This lets you reload a previously saved list of hits. The extension
must be ".hit" for this to work, but the program also understands the syntax
of a Trace log file. So if you were to save a Trace window onto a ".hit"
file (or to rename a log file in such a way), you would be able to display
it in a Hitmap Window.
Note that a trace log only reports the first address of an instruction acquisition (either assembly or GPL), whereas a hit list includes all such addresses. For instance MOV R1,@>2000 uses two memory words, but only the first one will be listed in a trace log. As a result, the hitmap for instruction acqusition will have a dot-pattern appearance. This is even more pronounced with GPL, where instructions can be upto 32 bytes in lenght.
Window --> Resize
Restores the default size of the Hitmap Window.
Disassemble
This item is only enabled with cpu memory and GROM. It opens a Disassembly
Window (or reuses the first one that was open, if any) and sets it to display
the address of the byte on which you right-clicked.
View memory
This item opens (or reuses) a Memory Window, and sets it so as to display
the current memory type beginning with the location of the byte you right-clicked
on. The current settings for Device and Page/Base are not modified. This
item is disabled when viewing CRU hits.
Peek address
This items calls a Watch Variable setup window, preset with the address
of the byte (or bit for CRU) on which you right clicked. This gives you
a chance to check the current value of this address, and possibly to modify
it (by entering a new one and clicking [Set]). Once done, you could either
click [Done] to dismiss the dialog, or [Watch] to place this address into
a list of watched variables.
Set breakpoint
This items call up the list of breakpoints if it isn't already displayed,
and the dialog it uses to create a new breakpoint. The breakpoint type
and address are preset according to the type of memory you selected. For
cpu and GROM memory, a PC breakpoint is assumed if you are viewing instructions,
a memory breakpoint otherwise. The Read and Write boxes in the breakpoint
dialog are preset to match those in the current pane of the Hitmap Window.
You can edit the breakpoint and click [Done] to install it, of [Cancel]
to abort the operation.
Wipe shown
This resets the counters for the type of memory currently displayed.
Only the selected counters (read, write or instructions) will be erased.
Also, in cased the zoom factor does not allow to display the whole memory
range, only the currently displayed addresses will be reset.
Wipe selected
This is very similar to the above, except that the range of counters
to reset is that specified on the right of the tab control, in the "Address"
and "to" fields.
[New] This button appends a new bus event at the bottom of the
list. To insert an event elsewhere in the list, right-click on the desired
position and select "insert" from the pop-up menu.
[Delete] This button deletes all the events that are currently
highlighted (in the first column). Alternatively, you can delete an invidual
event by right-clicking on it and selecting "delete" from the pop-up menu.
[Transmit] This buttons processes the next event in the bus
list. Timing delays are not observed, nor are STOP statments.
Auto. When this box is checked, the next bus event will be automatically
processed each time the Bus window is updated. This happens after each
instruction in "Step" and "Walk" mode. In "Jog" mode it happens after the
number of instruction you selected with Setup-->Options-->Execute. In "Run"
mode it happens each time the screen is updated, which is every 20 milliseconds
at the very least.
Send frame packets. This checkbox is only visible with the USB
device controller bus. Checking it causes the controller to believe it
received a valid frame packet every millisecond, thereby incrementing the
frame counter and preventing the controller from going "suspended". If
you don't tick this box, you will have to include SOF packets in your script,
otherwise the controller will think the bus is suspended. If this were
to happen, the controller would internally generate pseudo-SOF signals
(and interrupts, if enabled), and may enter suspended mode after 3 milliseconds,
unless the internal pull-up resistor is disabled (mode register bit >01).
All bus tabs begin with the same three columns
PIO bus:
STOP. Prevents automatic transmission for proceeding any further. You can bypass this command with the [Transmit] button, though.
WAIT. Holds transmission until the various simulated lines match the values specified in the other columns. Normally, you would only use input fields here (e.g. Hin and Sin) since the simulation cannot influence output fields, but it's entirely up to you. You can also wait for a specific value on the PIO or serial data port. As long as one of the values you specified is not matched, the script remains on this event and keeps checking the bus. Once all the correct values are found on the bus, the pointer can move to the next line (it is executed immediately in automatic mode, but you will need to click [Transmit] again in manual mode). If you wish, you can invert the condition by including a ! before or after WAIT, in which case transmission will continue if at least one of the specified fields does not match the bus. This allows you to implement OR conditions by inverting all the specified fields: WAIT High [or] High can be coded as WAIT ! Low [and] Low.
WHILE. Opens a loop that is closed by a LOOP statement. The loop will be entered if the current bus condition matches all the fields you cared to specify. Otherwise the pointer is transfered to the instruction immediately following the matching LOOP statement, further down the scripts. Just like WAIT, you can invert the condition by including a ! together with WHILE. You can nest as many loops as you wish, if a matching LOOP cannot be found, the script is terminated.
LOOP. Closes a "while" loop. The pointer is returned to the matching WHILE statment, which is evaluated again.
REPEAT. Opens a "repeat until" loop. This statment is ignored for transmission purposes.
UNTIL. Closes a loop opened by REPEAT. Execution will proceed past that point only if the bus matches all specified fields. Otherwise, the pointer is returned to the line immediately following the matching REPEAT, upstream of the current location. If a REPEAT cannot be found, the pointer is placed on the first line. Note that WAIT can be considered a special case of a one-line "repeat until" loop.
FOR. Opens a loop closed by a NEXT statment. Normally, FOR should be followed with a number (hexadecimal) indicating the number of times the loop should be repeated. This number will be copied into the Dir column, provided that the latter column does not already contain a valid number. Each time the FOR statment is reaches, the value in the "Dir" field is decremented by one. When it reaches zero, it is reinitialized to the value found after FOR in the "When" field and the cursor is moved past the matching NEXT statement further down the script. FOR-NEXT statments can be nested ad infinitum. If a matching NEXT is not found, the script is terminated.
NEXT. Returns the cursor to the matching FOR statment, upstream. If none is found, the cursor is placed on the first line.
IF. Opens a conditional block. If the bus matches all specified fields, execution continues with the next line. Otherwise, the pointer is moved down to the next ELSE, ELSEIF or ENDIF statment (which ever comes first). You can invert these outcomes by including a ! with the IF (i.e. execution continues if the bus doesn't match one of the specified fields). You can nest IF statments as much as you like.
ELSEIF. Works just like the above. In fact IF and ELSEIF are completely interchangeable.
ELSE. When the cursor reaches this point, it is moved to the line following the matching ENDIF further down the script. If none is found, the script is terminated. Note that all ENDIFs must preceede the ELSE, otherwise they would be ignored.
ENDIF. Marks the end of a conditonal block. This statment is ignored for transmission purposes.
Note that the three types of loops ignore each other, and could thus be interlaced (e.g. REPEAT - WHILE - UNTIL- LOOP) without causing an error. This is also true when mixing loops and IF statments. Thus, exercise due caution when structuring your script.
GOSUB. This calls a subroutine identified by a SUB statement. The name of the subroutine should appear in the "Dir" column and match exactly the "Dir" column in the SUB statement. The other columns can be used to pass parameters to the subroutine, or to receive a return value. To receive a return value, a column should contain an equal sign. Anything that's left of the = is considered a parameter and won't be touched. Upon return, the subroutine may place its return value on the right of the = sign, replacing anything that's there. If you wish to accumulate return values (e.g. if your GOSUB is within a loop), include a vertical bar | on the right of the equal sign: the return value will be inserted before the | without deleting anything.
SUB. This marks the beginning of a subroutine. When execution encounters this line, it skips ahead to the corresponding SUBEND, or to the end of the script if none is found. The only way to enter a subroutine is with GOSUB, which will begin transmission on the line following SUB. Within the subroutine, you can use a % sign in place of data in columns 4 to 10. When it encounters a % sign, the program replaces it with the contents of the corresponding column in the GOSUB line that called the subroutine (upto the first = sign, if any). The % sign persists, so that parameters can be passed again next time the subroutine is executed.
RETURN. Leaves the subroutine and returns to the line immediately following the GOSUB that called it. Optionally, you can return a parameter, by including a name beginning with $ in column 2. This name should appear in the "When" column of another line (possibly after a timing command), and identifies this line as the one that contains the return value. Any column in the GOSUB statment that contains a = sign will be patched with data taken from this line.
SUBEND. Is exacly equivalent to RETURN, but can only appear at the end of the subroutine. There must be one and only one SUBEND, whereas you may use as many intermediary RETURN as you wish (e.g. within various IF and ELSEIF blocks).
For example, you could do something like this:
When Dir PIO Hout Hin Sout
Sin
GOSUB Send 12
GOSUB Get =
STOP
SUB Send
Wr
High
WAIT
Low
Wr %
Wr
Low
WAIT
High
SUBEND
SUB Get
Wr
Low
WAIT
Low
$here Rd
Wr
High
WAIT
High
SUBEND $here
The first line calls the "Send" subroutine. The subroutine synshronizes with the DSRs by setting Hout high and waiting for Hin to go low. Then it outputs byte >12, taken from the GOSUB line, onto the PIO bus. Upon execution, this line will become Wr 12% Finally, the subroutine shakes hands with the DSRs again by setting Hout low and waiting for Hin to toggle before it returns.
The second line calls the "Get" subroutine, which inputs a byte from
the PIO in the line labeled "$here", synchronizing with the DSRs in a manner
similar to the above. Upon return, the subroutine will copy the received
value after the = sign in line 2. Assuming the received value is >34, line
2 will thus become: GOSUB Get =34
File --> Open
When opening a file with a .bus extension, reloads a script into a
new Bus window.
View --> Lines
Allows you to specify the number of lines to display in the list control,
valid values are 1 to 53. The command also adjust the width of the
control to match that of the window, then performs an implicit Window -->
Resize.
Window --> Resize
Adjusts the dimensions of the window to match the list control.
Insert
Creates a new bus event and inserts it before the event you right-clicked
on.
Delete
Deletes the bus event you right-clicked on.
Jump here
Moves the transmission pointer onto the event you clicked on. This
will be the next event to be executed.
View memory
This item is only available for the USB tabs. It allows you to view
the contents of the ISP1161 memory in a Memory window. Even though you
cannot do this with the real hardware, the simulation allow it: the device
controller memory appears at address >5000, pages >5000 to >500F for the
sixteen endpoints (beware there are two endpoints 0, in pages >5000 and
>5001, so endpoint 1 is in page >5002, etc). If an enpoint has a dual stacks,
both stacks are displayed consecutively. If an endpoint is inactive, the
Memory window will be empty. You can also manually enter page >5100 to
view the entire DC memory (total size is >99E bytes for some strange reason).
The various tabs bear the ID of the supported devices, and cliking on one of them will display the property page dealing with this device. The various fields on a given page are used to setup the way the device is emulated, or to control the device directly (as opposed to programmatically). Obviously, emulated devices are easier to control than real ones, and you'll be able to do "impossible" things, like reading CRU output bits, or writing to ROM. If you disable the simulation, many controls will thus become unavailable.
Most panes begin with a few common fields. In the top frame you'll see two non-editable fields containing the device ID and its current CRU address (you can't change the ID, but you can modify the CRU address via the Setup --> CRU map menu command). If the device has a master switch, you'll also see a checkbox labelled "Switched on". This box has to be ticked for the emulated device to answer during program execution. However, direct access to a device via the various information windows, is always granted when you specify the device by name, even if it is switched off.
In the same frame, you'll see the memory blocks used to emulate the
device, and the PC files to which they correspond. Different devices may
have different numbers of files, or possibly none at all, but the general
structure is the same:
three fields display: the file name, the file size in bytes, and the
type of memory emulated. The latter can be: ROM, RAM, EPROM, or nv-RAM
(non-volatile, or battery-backed RAM). ROM, EEPROM and nvRAM are loaded
from file when the you launch Bug99. EEPROM and nvRAM are saved back to
file when Bug99 terminates. ROM and EEPROM are write-protected against
standard memory writes during program execution. To programatically write
to an EEPROM, use the same routine you would with a real device (e.g. write
an unlocking code, etc). The Memory window (and other information windows)
let you write freely to EEPROM and ROM, so be careful when using them.
Next to each file name is a [Change] button. When you click on it, you will first be asked whether the current memory contents should be saved to the current file. This happens whether the memory has been modified or not, for all memory types, and is meant to give you a chance to save a memory "snapshot". You can cancel the operation at this point, or answer by [Yes] or [No] to continue with saving. Unless you canceled, you will then be presented with a file selection dialog box, which gives you the option to reload memory from a pre-existing file. If your purpose was to just save the current state of the memory, dismiss the file selection dialog with [Cancel]. Otherwise, pick a file that contains a raw memory dump (.bin extension) and click [Open] to load it into memory.
Most devices are controlled via the CRU, and the relevent CRU bits are displayed with checkboxes, generally arranged in numerical order (i.e. with bit 0 on top). By convention, a checked box means '1', an unchecked box means '0'. Since CRU input bits can be totally distinct from CRU output bits, there may be two columns of boxes, one for output bits, one for input bits. Obviously, you cannot read output bits, nor set input bits with a real device, only with an emulated one. Thus, if you disable the simulation (with Setup --> System), the checkboxes for CRU output bits change into two small buttons: a [0] and a [1]. You can set or reset a CRU bit by clicking on the appropriate button, but you cannot know what its current status is. Conversely, you can view CRU input bits, but you cannot change them: only the hardware can.
Many peripheral cards also comprise dual-inline package switches (DIP-switches),
that let you control some functions of the card. Emulated devices use checkboxes
again to represent these switches. A ticked box means a closed switch,
an unchecked box means that the switch is open. Note that DIP-swiches
used to encode the CRU will not be represented with check boxes, instead
you should use the Setup --> CRU map command to alter the CRU address of
the card.
This pane allow you to directly control CRU bits, on any device
of your choosing. At the top of the page is an address field in which you
should enter the CRU address (the one you would place in R12) of the first
bit you want to access. Remember that only even addresses are valid. You
can also use the drop-down list to pick up a device by name. Once you've
entered the address, click the [=] button to activate it.
The page displays the status of the first 16 CRU bits as checkboxes,
starting at the selected address. Because CRU input bits do not necessarily
mirror output bits, the two types of bits are displayed in different columns.
In either case, a ticked checkbox means a '1' bit, an empty checkbox means
a '0' bit.You can change the address by using the 5 navigation buttons:
[^^] Previous device: address decreased by >0100
[^] Previous set of 16 bits: address decreased by >0020.
[=] Refresh the display at the current address. Use this after
you entered a new address manually.
[v] Next set of 16 bits: address increased by >0020.
[vv] Next device: address increased by >0100.
You can alter the value of any CRU bit by just checking/unchecking the corresponding checkbox. When accessing real device on the remotely controled TI-99/4A, you can only change output bits, and only read inputn bits. With emulated devices, however, you can read and write both types at will. The change becomes effective as soon as you toggle the checkbox. Note that you will get an error message if there are no devices aswering at this CRU address, or if more than one device answered.
[Set] Rather than manipulating individual bits, you can also entered a 16-bit value in one of the two edit boxes (one for input bits, one for output bits) and click the corresponding [Set] button. This always sets 16 bits at a time, even if you enter a number that could be encoded with fewer bits: implicit '0' bits are just added in front of the number you entered (e.g. 2 is understood as >0002).
For more info on the CRU, check this page.
This pane grants you direct control on the videoprocessor. Because
the VDP has no CRU interface, there are no CRU bits available on this page.
Type.The frame box at the top of the page lets you select the type of VDP chip that you want: the North-American version TMS9918a, which issues interrupts 60 times per second, or the European TMS9929a, which issues 50 interrupts per second.
Under the frame box you can see the contents of the various VDP registers, generally accompanied with a detailed breakdown. Remember that VR0-VR7 cannot be read on the real TI-99/4A, and VST cannot be written to. The emulation, of course, lets you do what you want. Just type in a new value, then click out of the field and it will be set.
Current address. The address in VDP RAM at which the next byte
will be written or read from. You must click the [Set] button to change
this value inside the simulation and/or the remote system.
VST. VDP status register. Int: interrupt pending. 5
spr: more than 4 sprites on a pixel row. Coinc: 2 sprites have
overlapping 'on' pixels. 5th sprite: number of the offending fifth
sprite on a pixel row.
VR0. Only two bits are relevant, Bit: bitmap mode, Ext:
external video input (not used on the TI-99/4A).
VR1. Setup register. 16: memory is >4000 bytes (rather
than >1000). On: screen is on. Int: generate interrupts.
Text:
text mode. Mult: Multicolor mode. Size: Sprite size. Mag:
sprite magnification.
VR2. Address of the screen image table in VDP RAM. The combo
box translates the register value into an address, and conversely. You
can also pick the address from the list.
VR3. Address of the color table in VDP RAM. Again, the combo
box translates the register value into an address, and conversely. In bitmap
mode, another box provides the value of the address mask.
VR4. Address of the character patter table in VDP RAM. A combo
box is used to translate the register contents, another to provide the
address mask in bitmap mode (the mask is combined with VR3 unless in text
mode).
VR5. Address of the sprite attributes table in VDP RAM. A text
box translates the register value into an address, and conversely. No drop-list
here, because there are just too many valid addresses (every >20 bytes).
VR6. Address of the sprite pattern table in VDP RAM. A combo
box translates the register value into an address, and conversely.
VR7. Screen color (background color in text mode) and foreground
color in text mode. The drop-down lists let you pick the color by name.
Quick set. Rather than setting up the VDP one register at a time, you could use this drop-list to load one of the preset configurations: power-up time, TI Basic, Extended Basic, Editor Assembler cartridge (in run mode), TI-Writer cartridge, and p-code card. VDP registers VR0 through VR7 are loaded with the proper values when you close the drop-list.
If you have disabled the simulation, there is no way for the program to read the value of the VDP register from the remote system (these are write-only registers), nor can it read back the current VDP address. The property sheet will display the last values you entered manually, but if anything was changed programmatically (by running a program on the remote system), you will not see the changes. By contrast, the VDP status register is read-only, so you can always read it, byt you cannot modify it if the simulation is disabled.
For more details on the VPD see this page.
This page lets you control the Horizon Ramdisk. The top frame features
a main switch and the two files used by the emulator: one for the DSRs
and one for the Ramdisk memory itself. In both cases, the memory type should
be nvRAM, since the ramdisk is made of battery-backed SRAM chips. Note
that, because there is room for 12 SRAM chips on the board, the total Ramdisk
memory should be a multiple of three. If you pick a power of two instead
(e.g. 4 megs), it will confuse the CFG configuration program which will
take forever and eventually misdiagnose the type of Ramdisk.
Only two CRU output bits are displayed with checkboxes, bit 0 and 15.
The others make up the page number (except for bit 14 that is not used).
Card on (bit 0): makes the card memory appear in the DSR space,
at >4000-5FFF. The DSR chip maps at >4000-57FF and is not affected by the
page number, the Ramdisk memory maps at >5800-5FFF.
Rambo on (bit 15): triggers the RAMBO modification, which makes
Ramdisk memory available at >6000-7FFF.
Page (bits 1-14): selects which portion of the Ramdisk memory
will appear at >5800-5FFF. Each page is >800-byte long and the maximum
number of pages depends on the size of the Ramdisk; it is indicated further
on the right, in the "Total" field. Click the [Set] button to modify the
current page number. Because the Ramdisk does not have CRU input bits,
the page number cannot be read back from the remote TI-99/4A, but the simulation
has no such problem.
This pane also lets you modify the configuration and the contents of the Ramdisk. It assumes that the DSR loaded is ROS 8.14 or something similar enough so that it can find the necessary information at predefined addresses. For each of the 10 virtual drives provided by the ROS, you can read and possibly change:
[Import] these buttons let you upload a file into Ramdisk memory, at the location corresponding to a virtual drive. The file should contain a disk image with sectors in numerical order (normally, a .dsk file). The command first checks that the file contains a valid sector 0 image, then checks the disk size announced in sector 0 against the actual size of the PC file. If there is a mismatch, you will be asked whether to use the actual size, or the size stated in sector 0. The command then makes sure that the disk can fit into the virtual drive. If that's not the case, an error message is displayed, which gives you the option to abort the operation. If you chose to continue, you should be aware that disks larger than the drive will be truncated. Smaller disks are loaded normally, and the unused part of the drive remains unchanged.
Rambo: Below the list of drives is some info regarding Rambo mode: the first page used by the Rambo subroutines, the resulting number of available pages, and the total number of possible pages as calculated by the Ramdisk configuration program. The latter may or may not match the total number of pages calculated from the disk size. You can change the number of the first page, which will then modify the size field. Note that each Rambo page corresponds to 4 Ramdisk pages (displayed at >6000, >7000, >6800, and >7800, in that order), thus the page number is always a multiple of 4. You can also type in (or select from the drop box) "None" which disables Rambo mode, or "Rest" which selects the smallest possible start page that does not overlap with the drives. Note that there may be a gap left, if the total size used up by the drives is not a multiple of 4.
ROS: As you may know, the DSR chip only maps at >4000-57FF, which
gives you 6K of memory. The area >5800-5FFF is reserved for ramdisk pages
(except in Rambo mode, in which the DSR chip maps onto the whole range
>4000-5FFF. The "hidden" part contains the Rambo DSR, i.e. opcode >B0).
Since the DSRs are bigger than 6K, an extra 2K was allocated by the simple
expedient of reserving a Ramdisk page for it. By default, this is page
0 and the first drive starts at page 1, but the DSRs would allow any page
here. You can change it, but make sure that the corresponding drive page
contains the rest of the DSRs. The next field displays the version number
taken from that page, and it should read something like "8.14B", otherwise
you are in trouble. Also note that the Ramdisk configuration program does
not save/load this part of the DSRs in your ROS file, it loads it from
an internal copy within the CFG program.
Finally, there is a checkbox that lets you toggle autostart mode on/off.
This does the same as CALL AO and CALL AF, only without the need to enter
TI-Basic.
For more information on the Horizon Ramdisk, check this
page.
Nothing exciting here, I'm afraid: no CRU address, no main switch,
no special control funtions. Just one memory block, which is RAM and thus
normally does not use a file. A filename is provided though, so you can
save a "snapshot" of the memory if you so wish.
The p-code card uses two files: a 12K (>3000 bytes) file for the
DSR ROMs, and a 64K file for the internal GROMs. Note that these GROMs
are accessed via the DSR space, at base address >5FDC, so are not visible
to the general TI-99/4A operating system.
Grom address. This field displays the current GROM address. To change it, enter a new value and click [Set].
CRU bits. There are only two CRU output bits with this card: Bit 0 turns the DSR space on/off, and bit 128 toggles between two pages in the >5000-5FFF area.
Be aware that, for a reason that I do not understand, the p-code card simulation takes forever to boot (over 30 seconds). So be patient...
For more information on the p-code card, see this
page.
The AMS and SAMS card use only one RAM file, with a size of 1 meg for SAMS and only 512K for AEMS. The HAMS card supports RAM and EEPROM upto a cumulated maximum of 4 megs, and there is one file for each memory type.
Pages. This frame displays the 16 registers of the 74LS612 memory mapper. Each corresponds to a 4K memory block >0000-0FFF, >1000-1FFF, etc. The contents of the register indicates which memory page will show at these addresses. Page numbers range from >80 through >FF with the AEMS card, >00 through >FF with the SAMS card, and >000 through >FFF with the HAMS card. Be aware that only the HAMS card can map memory in the whole addressing space, the AEMS card only handles >A000 through >FFFF and the SAMS card handles >2000-3FFF and >A000-FFFF. The remaining registers are not used with these cards.
CRU bits and DIP-switches. The AEMS and SAMS cards have only two CRU output bits, bit 0 and 1. The HAMS card uses 6 extra CRU bits and 3 DIP-switches to control mapping in the "non-memory expansion" portions of the addressing space.
The DIP-switches control the default behaviour of the HAMS card, when all CRU bits are zero: will the card answer at >0000-1FFF (normally reserved for the console ROMs), at >8000-83FFF (console "scratch-pad" RAM), and in the normal memory expansion space (>2000-3FFF and >A000-FFFF).
CRU bit 0 turns the DSR space on, which is required to access the mapper's
registers programatically.
CRU bit 1 toggles the mapping mode: when off the mapper is "transparent",
i.e. page 0 maps at >0000-0FFF, page 1 at >1000-1FFF, etc. When CRU bit
1 is on (box checked), the 74LS612 is in mapping mode, i.e. it uses the
pages specified in the various registers.
CRU bit 2, when set to "1", disables mapping at >0000-1FFF, in case
it was enabled by the DIP-switch. This bit has no effect with the DIP-switch
disabled mapping, nor on the AEMS and SAMS cards.
CRU bit 3, when set, puts the HAMS card in SAMS-compatibility mode,
i.e. restricts its internal memory to the first layer of chips.
CRU bit 4 determines what appears in the area >4000-5FFF when CRU bit
0 is set. If bit 4 is set, the mappers register appear repeatedly in the
whole area. If bit 4 is not set, registers only appear at >5FE0-5FFF whereas
the selected page maps at >4000-5FDF. This allows you to implement DSRs
for the card.
CRU bit 5 enables mapping at >6000-7FFF (cartridge ROM area) when set.
CRU bit 6 disables mapping at >8000-83FF, assuming it was allowed by
the DIP-switch.
CRU bit 7 turns the area >4000-5FFF into "write-only" memory, which
is needed to send the unlocking code to EEPROM chips, in order to write
to them.
Chips. The HAMS card supports a total of 16 pairs of 512K memory chips, arranged in 4 layers. Two hardware jumpers, Lnk1 and Lnk2, select how many layers there are. Each pair of chips can be either SRAM or EEPROM, and two types of Flash-EEPROMs are supported, sectored chips like the 29C040 and registered chips like the 29F040 (this distinction in important when it comes to writing to the chips). The "Chips" frame lets you select how many layers you have, and the type of each chip. Be aware that the default layer at power-up time is layer 2, whereas layer 1 is the only one used in SAMS-compatibility mode (and should thus consists only of SRAM). Selecting "pages..." as a chip type calls a dialog box that tells you which page numbers correspond to this chip (the chip type remains unchanged).
For more information on the AEMS and SAMS card, see this
page. For a description of the HAMS card, see here.
Bases. The two sets of GRAMs always answer to base addresses that are >0020 apart, but you can choose which these should be. Normally, you would select >9800+9820, but you are free to pick another value (e.g. to avoid conflicts with another GRAM device).
CRU bits. The card features 8 CRU output bits.
Bit 0 turns on ROM memory in the DSR space >4000-5FFF.
Bit 1 turns off RAM memory in the cartridge bank space >6000-7FFF (it's
inverted, so that banks are on by default).
Bit 2 and 3 control reading via the two GRAM ports. Writing to GRAM
is never disabled (quite annoyingly). When both bits are 0, both ports
are enabled. To disable the secondary port (address >982x) set bit
3 to 1. To disable the primary port (>980x), you must set both bit 2 and
bit 3. As a general rule, you would leave bit 2 set, and control both ports
via bit 3. But there may be cases when you want to enable the primary port
while disabling the secondary (for instance when a cartridge ROM would
appear in the secondary port and confuse the system). To do so, reset bit
2 and set bit 3.
Bit 4 write-protects the cartridge space at >6000-7FFF, effectively
turning it to a ROM.
Bit 5 enables GRAM in the range >0000-5FFF, normally reserved for the
console GROMs.
Bit 6 determines whether the page appearing at >7000-7FFF is the software-selected
(as shown in the "Ram page" field), or a default page. The default page
number (from 0 to 3) is preset with DIP-switches on the remote system,
and can be changed via the drop-list box with the simulation.
Bit 7 enables cartridge bank switching by writing to the cartridge
space: write at >6000 to selecte page 0, at >6002 for page 1, upto >601E
for page 15.
Gram address displays the current address counter, which is common
to both GRAM ports. To change it, enter a new value and click [Set].
Ram page displays the currently selected page to appear at >7000-7FFF.
To change it, enter a value from 0 to >F and click [Set]. Since RAM pages
are implemented with the same memory chip than the second GRAM port, each
RAM page overlaps a given portion of the second GRAM. A message appears
under the page number to let you know which GRAM addresses correspond to
the current RAM page.
For more information on the german GramKarte, check this
page.
The TMS9901 is the interrupt and peripheral controller within the
TI-99/4a console. It is a very complex and versatile chip, but the way
it is wired inside the console kind of limits its abilities. The chip is
entirely controlled via the CRU, with 32 output bits and 32 input bits
at address >0000. So, if you wish to experiment with it, your probably
better accessing via the "CRU" property page. The "9901" property page
only deals with the bits that are used within the console.
Interrupts: Only two input lines are effectively used for interrupt control, one for VDP interrupts and one for PE-box interrupts. The check boxes on the left side (CRU output bits 1 and 2) enable interrupts when checked. Those on the right side (input bits 1 and 2) indicate the status of these interrupt pins. Note that, since interrupts are active low, an empty box means that an interrupt is pending.
Keyboard: With the column drop list, you can select which part of the keyboard (or which joystick) is currently active. The boxes on the right indicate whether a key is pressed. Since pressing a key connects it to the ground, a key down shows up as an empty box. A CRU output bit allows to toggle the alpha-lock key, which returns its result in the fifth input line (same as Fctn).
Cassette: Four CRU output bits respectively control: the motors for the two cassette players, the audio gate (i.e. whether you will hear what's read from the tape through the monitor), and the bit currently written to the tape. One input bit returns the bit currently read from the tape. Cassette tapes are not emulated withing Bug99.
Timer: "Access" corresponds to CRU output bit 0 and puts the timer in access mode, freezing the read value and changing the meaning of CRU bits 1 through 15. The three text boxes display the contents of the three timer registers within the simulation: the value that was loaded (and will be reloaded when the counter reaches zero), the current value, and the value that was current when the timer was placed in access mode. You can modify these values and press [Set] to commit them to the TMS9901. Leaving access mode will start the timer. The check box on the right indicates whether an interrupt is pending, which happens the first time the counter reaches zero. This interrupt will be seen by the TMS9901 as if coming from interrupt pin I3.
Pins: The check boxes display the status of the I/O pins in the TMS9901, while the drop lists let you alter their function. There are three categories of pins. P0 through P6 are pure I/O pins: they are initially inputs (and cannot generate interrupts) but can be programmed as outputs. Pins I1 through I6 are pure input pins, but you can decide whether or not they will trigger interrupts when low. The remaining pins, P7/I15 through P15/I7 can be programmed either as input, interrupt, or output pins. Normally, an output pin cannot be programmed back to an input (or interrupt), but the simulation will let you do it with these drop-lists. The only way to bring all pins back to input mode with the real TI-99/4A is to perform a reset, either a hardware reset, or a software reset (which leaves the timer intact). You can simulate the later by pressing the [Soft reset] button. The IntReq* pin signals the microprocessor that an interrupt has been detected by the TMS9901, and is active low. There are 4 additional pins on the TMS9901 that can pass the interrupt number to the microprocessor, but unfortunately these pins are not connected in the TI-99/4A console: the microprocessor sees all interrupts as #1.
For more information on the TMS9901, check this
page.
The simulation uses four files, three of which emulate the three memory
blocks in the standard console.
The first file implements console GROM memory as a >5800 bytes block.
Each GROM is actually only >1800 bytes, but the file is monolithic and
includes fillers for the area >1800-1FFF and >3800-3FFF that are not accessed
programatically.
The second file is 8K and corresponds to the console ROMs, at address
>0000-1FFF.
Then there is a 256-byte long file that implements the tiny amount
of RAM present in the console. Note that, due to incomplete address decoding
in the console, these >100 bytes map 4 times, at >8000-8FFF, >8100-81FF,
>8200-82FF and >8300-83FF.
Finally, there is one more file, which is used to emulate a console
modification I came up with: replacing ROMs with EEPROMs (see this
page for details). This file is 16K in length, allowing for two pages
at addresses >0000-1FFF.
Memory selection. A series of switches can be added to the console to turn off the various memories. This comes in handy with some GRAM cards and with my HAMS memory expansion card, which have the ability to answer within the console memory space. You can disable the scratch-pad RAM (>8300-83FF), the console ROMs (>0000-1FFF), and enable console EEPROMs (>0000-1FFF). Since EEPROMs chips are larger than ROMs, there are two EEPROM pages; you can select the second one with a CRU bits (assigned in Setup-->CRU map). Finally, yet another switch can write-protect the EEPROMs, which is critical given the number of program that write at address >0000, assuming this will have no effect...
The situation is a bit more complicated for GROMs. These are socketed chips so you can theoretically remove some and leave the others in place. In practice, most GRAM cards require that at least one GROM remains in the console (generally GROM 0), to return the current address minus one, something that is difficult to implement in hardware. The notable exception is the HSGPL card, with which you can remove all three GROMs. Finally, you could install a small switch that lets you temporarily turn all GROMs off, in the console and in the cartridge slot (see this page for details). This can be used with the HSGPL card, so you don't have to open your console every time. The emulation implements these various options via a drop list, where you pick which GROMs remain: All, GROM 0 only, None, or all present but switched off.
Wait states. This controls a series of console modifications I suggested, which allow you to selectively remove some of the 4 wait states when accessing peripheral memory. Each wait state is controlled by a distinct CRU bit, which are assigned via Setup-->CRU map. Note that some combinations of wait states should not be used. See this page for details.
Interrupts trigger NMI. This is a modification suggested by Jeff Brown, in which standard interrupts are intercepted by hardware to generate non-maskable interrupts. See this page for details. The mechanism is controlled by a CRU bit, which can be assigned in Setup-->CRU map.
Clock speed. This lets you emulate the various clock speeds that
can be implemented in the console. Normally it is 3 MHz, but many modifications
have been described to speed it up by changing the crystal. I came up with
a different solution, using oscillators, which has the advantage that clock
speed can be toggled by software, between 3 and 4 MHz. If you select this
option in the drop list, the "High speed" box corresponds to a CRU bit
(defined in Setup-->CRU map) which switches from 3 MHz to 4 MHz. See this
page for details.
The simluation uses two files per cartridge, one for the GROMs and one for ROMs (note that some cartridges have only GROM or only ROM, in which case only one file is used). If a cartridge contains more than one GROM, the contents of the GROMs should be concatenated in the same file, possibly adding a spacer if GROMs are smaller than >2000 bytes. Similarly, if there are several ROM pages, they should be placed in order within a single file. This can be done with an hexadecimal editor, or with the DOS COPY command. You could also load independent files with multiple File-->Load commands, then save them together with one File-->Dump operation.
Slot. This emulates the selector switch on the Widget and determines which cartridge will answer. Note that you are free to leave any slot empty, or even all three. You can also place the selector on "off" which emulates the situation when you have no cartridge plugged in.
Quick load. Lets you quickly load a cartridge in the currently selected slot. Just pick one from the drop list and the relevant file(s) will be loaded. Alternatively you can select -empty slot- to emulate cartridge removal. Note that I do not provide cartridge images with this package. If you have a hardware cartridge, it is quite easy to upload it to your PC with File-->Dump.
Multibase Widget. Tick this box if you wish to emulate a Widget modified at per my instructions. See this page for details.
Bases. Here you define which base corresponds to which slot,
in a "multibase" Widget. Note that, due to hardware design, not all configurations
are possible (at least one address line must be low). If you pick a wrong
combination, you'll get an error message.
Memory. The card supports a 512K SRAM chip, to be used with the RTC65271 and bq4847 clocks, or a combined SRAM+clock chip which can be either bq4842 (128K) or bq4852 (512K). This memory (DSR RAM) will be implemented as RAM with the RTC65271 and non-volatile RAM with the other chips.In addition, the RTC65271 clock features an extra 4K of RAM, arranged as 128 pages of 32 bytes. This is emulated via a nvRAM file, which is not used by the other clock chips.
Drives. The simulation uses two more files on the PC to emulate the master and slave drives, but you can dispense with the slave drive if you wish. File size is illimited (as long as it fits on your PC hard drive, that is). Note that these are real files, not memory files, which means that any change is written to disk immediately, rather than when you end the program.
CRU bits. The IDE card is controlled by 8 CRU output bits, together
with 8 CRU input bits.
Output bit 0 enables access to the DSR space at >4000-5FFF.
Ouput bit, 1 when matching DIP-switch 1, causes device registers to
map at >4000-40FF. Otherwise the SRAM maps in the whole >4000-5FFF range.
Output bit 2 allows page switching upon writing to >4000-4FFF in a
method similar to that used by cartridges. Write at >4000 for page 0, >4002,
for page 1, >4004 for page 2, etc.
Output bit 3, when '0', forces page # 0 in the area >4000-4FFF, no
matter what page has been selected. The selected page still appears at
>5000-5FFF.
Output bit 4 enables memory mapping to the cartridge space, at >6000-7FFF.
Ouput bit 5 write-protects the SRAM (useful when switching pages).
Ouput bit 6 enables interrupts and bit 7-driven reset.
Output bit 7 only works when bit 6 is set. When '0' it causes a hardware
reset of both drives.
Input bit 0 does not work, due to a hardware design flaw. It was supposed
to indicate an IDE interrupt, but I didn't realize that the interrupt line
is only active when accessing the IDE port, so in practice you cannot read
it.
Input bit 1 returns the position of DIP-switch 1.Input bit 2 indicates
whether a clock interrupt is pending. It is active-low, so a "0" means
an interrupt.
Input bit 3 returns the status of the IORDY line in the IDE bus. A
"1" means that the drives are ready.
Input bits 4 and 5 read back ouput bits 4 and 5.
Input bits 6 and 7 are not used.
DIP-switches. There are four DIP-switches on the card. The first
two are used only with the RTC65271 clock, the last two are not used.
Switch 1 decides if the SRAM or the clock XRAM will appear at >4000-401F
upon power-up. This allows you to boot from the clock RAM, which is battery
backed.
Switch 2, when closed, resets the RTC65271 upon power up. This is useful
to clear an interrupt condition that may have occured while the system
was off (the clock keeps ticking and reacts to alarms). Such an interrupt
would cause a system lockup when booting from the clock, because the interrupt
service routine is not be present at power-up time.
SRAM page. This is the number of the current SRAM page. To change
it, enter a new value and click the corresponding [Set] button. Valid values
are 0 through >3F with the bq4842 clock, and 0 through >FF for all other
clocks.
Clock page. This is only relevant to the RTC65271 chip. It is
the page number for the internal clock RAM. To change it, enter a new value
and click the corresponding [Set] button. Valid values are 0 through >7F.
Clock. The first drop-list lets you decide which clock chip you wish to emulate (if any). The second decides on how the simulation calculates elapsed time: it can either use the clock on your PC (i.e. real time), or the time "elapsed" during simulation. The difference becomes obvious when you stop execution: the PC clock keeps running, but the emulated clock stops.
Clock registers. These vary slightly according to the clock type.
Time is displayed in hours : minutes : seconds and possibly hundredth of
second. Date is in day / month / year / and day of the week notation. Alarm
is in hours : minute : second, and alarm day when available. Exceptionally,
input is in decimal notation for these.
Each clock chip also features 4 function registers, which have different
roles with the various chips. Input is in hexadecimal, as ususal. Click
on the corresponding [?] button to get a breakdown of the various bits
in a given register. Click [Done] to dismiss the dialog, or [Set] to introduce
changes.
You can also access any register by selecting its number from the drop-list:
its contents appears in the neighbouring text field, in hexadecimal notation.
Note that all clocks have extra registers not detailed in the "Clock registers"
frame: 64 for the RTC65217 and 16 for the other clocks.
Click [Read] to update the contents of all registers, [Set] to send
new values to the clock chip.
For more details on the IDE card, check this page.
Memory. The card features a single 4K ROM chip, mapping at >4000-4FFF. The PIO port maps repeatedly from >5000 to >5FFF.
CRU bits. There are 8 CRU output bits and 8 CRU input bits at the card's base address. This normally is >1300, but it can be modified to appear at >1500, which lets you have two RS232 card in your system. You can select the address you want in Setup-->CRU map, but only one card can be emulated.
Output bit 0 enables access to the DSR space, at >4000-5FFF.
Output bit 1 puts the PIO port in input mode when "1", in output mode
when "0".
Output bit 2 controls the "handshake out" line in the PIO port.
Output bit 3 controls the "spare out" line in the PIO port.
Output bit 4 is not used.
Output bit 5 controls the CTS-1 (clear to send) line in RS232 port.
Output bit 6 controls the CTS-2 line in the RS232 port.
Output bit 7 turns the card's front LED on.
Input bit 0 always reads "0".
Input bits 1, 4, 5, 6, and 7 read the corresponding output bits.
Input bit 2 returns the status of the "handshake in" line in the PIO
port.
Input bit 3 returns the status of the "spare in" line in the PIO port.
TMS9902 chips. The RS232 card also contains two TMS9902 serial transmitters, each controlled by 32 CRU output bits and 32 CRU input bits. The first TMS9902 answers at the card's CRU address plus >0040 (i.e. >1340 or >1540), the second at the card's address plus >0080. The drop-list lets you select which TMS9902 you want to access. The relevant bits are then grouped by functions in several frames.
Registers. The drop box lets you select which internal register
you wish to access in the TMS9902: reception, emission, output rate, input
rate, interval, or control. The contents of the register are displayed
in the neighbouring text box. You can modify this value and click [Set]
to write it into the register. Click [Read] to update the current value.
Loading
means that the register is currently being loaded and cannot be accessed.
Reset
(bit 31) can be toggled on/off to trigger a software reset of the TMS9902.
Test
mode (bit 15) internally connects output to input to allow testing.
Transmission. Reports on the current transmission status. Break
this output bit can be used to abort transmission.
Interrupts. The boxes on the left (CRU output bits) enable the
various interrupt. Those on the right (CRU input bits) reports the current
interrupt status.
Errors. Report error conditions, if any.
Pins. Return the state of the various pins of the TMS9902. The
RTS, DSR, and CTS bits report inverted values (note that the CTS and DSR
pins are connected together and take their input from the DTR line in the
RS232 bus). The one output bit controls the RTS pin.
For more details on the RS232 card, check this
page.
Memory. The card has two types of memory. A Flash-EEPROM chip that can be either 8 megs or 4 megs, depending on how much money you were willing to spend. The EEPROM chips maps at >4000-4FFF in the card DSR space. There is also one megabyte of SRAM (not battery backed), which maps at >5000-5FFF.
CRU interface. The card is controlled via 24 CRU output bits,
most of which encode the page numbers for the EEPROM and the SRAM. There
are also 8 input bits used to return various type of information.
Output bit 0 enables access to the DSR space, at >4000-5FFF.
Output bit 1 causes the Smartmedia card to map at >4FF0-4FFF, and the
ISP1161 dual USB controller to map at >5FF0-5FFF. When bit 1 is "0", EEPROM
and SRAM occupy the whole DSR memory range.
Output bit 2 enables interrupts.
Output bit 3 enables the Smartmedia card.
Output bit 4 enables writing to the Flash-EEPROM, provided DIP-switch
1 also allows it. In any case, it disables reading from the EEPROM.
Output bits 5 to 16 make up the page number for the EEPROM.
Output bits 17 to 24 make up the page number for the SRAM.
Input bit 0 signals an interrupt from the USB host controller. It is
active-low, so a '0' means an interrupt is pending.
Input bit 1 signals an interrupt from the USB device controller. It
also is active-low.
Input bit 2 signals that the USB host controller is in suspended mode.
Input bit 3 signals that the USB device controller is in suspended
mode.
Input bit 4 signals that the Flash-EEPROM is busy (e.g. being erased)
and should not be accessed.
Input bit 5, when '0', signals that the Smartmedia card is busy.
Input bit 6 signals that Smartmedia card is present.
Input bit 7, when '0', signals that the Smartmedia card is write-protected.
DIP-switches. The card comprises 6 DIP-switches, 4 of which are
used to set the CRU address of the card. The remaining two switches have
the following functions:
DIP-switch 1 write-protects the Flash-EEPROM when open. It should be
closed to enable writing via CRU bit 4.
DIP-switch 2 is used to enforce write-protection of the Smartmedia
card at the hardware level. When this switch is open, the software can
ignore the write-protection signal.
SRAM page. This is the number of the SRAM page that appears at
>5000-5FFF. To change it, enter a new value and click [Set]. Valid values
are >00 through >FF.
EEPROM page. This is the number of the Flash-EEPROM page that
appears at >4000-4FFF. To change it, enter a new value and click [Set].
Valid values are >000 through >7FF with an 8-meg chip, and >000 through
>3FF with a 4-meg chip
Busy: This is the time in nanoseconds for which the chip will
be busy writing or erasing. It decrements every time you execute an instruction.
Changing this field to zero sets the "ready" bit (>80) in the status register,
entering a non-zero value resets the "ready" bit. Note that writing and
erasing are actually emulated at the beginning of the wait period, so there
is no harm in clearing this field immediately thereafter (in other words,
waiting is emulated, but not necessary).
Status: Displays the Strataflash status register. Click the
[?] button for a breakdown of the various bits. Note that setting the "ready"
bit will reset the "busy" timer.
Command: Shows which command is currently executing or has just
completed (note that some commands switch to "read status" when completed).
Click the [?] button for a description of the command. It is best that
you do not change this field, as most commands only work when programatically
written to a given address. The four read commands (FF: data, 70: status,
90: ID, and 98: query) are safe to use, though.
Config: Displays the configuration of the STS pin, which is
sensed via CRU bit 4. You should leave this as level-triggered mode (>00),
since the pulses generated in edge-triggered mode are much too short for
the TI-99/4A to detect. Thus, if you select a pulse mode, CRU input bit
4 cannot be used to sense when the chip is busy.
Locked: This 64-bit value shows which blocks are currently protected
against writing and erasing. Each block is 128 KB, i.e. 32 EEPROM pages.
The first block is >0000000000000001, whereas >0000000080000000 is the
last block for a 4-megabyte chip, and >8000000000000000 is the last block
for a 8-meg chip. Lock bits are saved as part of your workspace, and can
be altered as desired.
Filename: The PC file that hold the contents of a virtual Smartmedia card. Note that it is a real "hard disk" file, not a memory file, which means that any change to the emulated card will be saved immediately, rather than when you exit the program. Click [Change] to pick a new file, which be can either a binary file, or a .smc file comprising a 16-byte header with the card's characteristics. You will get a warning if the file does not contain a header, but the program will accept it and attempt to guess the card characteristics based on the file size. You can modify these characteristics later, if you so wish.
To create a new file you must first specify its size in the "Size field" since the program uses it to guess the cards characteristics. Then you can click [Change] and enter a non-existing file name. You will be asked if you wish to create the file and, if you said [Yes], a empty file will be created containing a Smartmedia header followed with the appropriate number of >FF bytes.
Size: As mentionned above, this field is only used when creating a new file. The rest of the time it simply displays the size of the current file. When specifying a size, make sure that it matches with the number of address bytes (i.e. the number of sectors) and the sector size. Remember than one of the address bytes is used to pass the offset within the sector, so a 3-byte address allows access to a maximum of 65536 sectors. The file can be smaller than the maximum size allowed by the addressing mode, but it shouldn't be larger (since the extra space would not be accessible).
[Wipe] Click this button to reformat the Smartmedia card, i.e. filling the file with >FF bytes. This is one of the few cases when Bug99 will ask you for confirmation of a command.
Inserted: This checkbox lets you emulate insertion and removal
of a Smartmedia card.
Write-protected: This emulates write-protection of a card (which
is normally achieved by sticking a small conductive patch on top of the
card).
Address bytes: There are different internal formats among Smartmedia
cards. Old cards have 3-byte addresses, whereas newer (and bigger) cards
use 4 or 5 bytes. Pick you choice from the drop list or enter a value manually.
Bytes/sector: Old cards had 256 bytes per sector, plus 8 bytes
of extra info. Newer cards have 512 bytes per sector, plus 16 bytes of
info.
Sectors/block: Smartmedia cards are erased one block at a time,
but cards differ on how many sectors a block represents. As far as I know,
it could be either 16 or 32. Cards larger than 8 megs erase 32 sectors,
smaller cards use 16.
Chip ID: Here you can enter the two bytes that the card will
return in answer to the "read ID" command: the manufacturer ID and the
chip ID. On some models, the ID is 4-byte long, with the third byte fixed
as A5. Bytes are arranged from right to left in this field, i.e. the least
significant byte will be read first. The drop-list provides default values
for various chip sizes.
Extended ID: Some Smartmedia cards implement a "read extended
ID" command, which returns one byte of data. Here you can enter the value
to be returned by this command (generally >20 to indicate that the card
supports multiple writes).
Flags: An internal variable in which the simulation keeps various
elements of info about the emulated card. Click [?] for details of the
various bits. Most of these correspond to the flags saved in the Smartmedia
file header (see below). Beware that, if you change the "No file header"
flag, you will need to reformat the file by clicking [Wipe].
Command: This is the software command that the Smartmedia is
currently processing, or has just completed. Click [?] for an explanation.
It is better if you do not change this command manually.
Status: The status register of the emulated Smartmedia card.
Click the [?] button for a breakdown the the various bits. If you change
one, click [Set].
Smartmedia image files should have a .smc extension (for SmartMedia Card). Such files begin with a 16-byte header consisting in the following fields:
TAG TEXT 'SM' identification characters FLAGS BYTE >00 >80 protected, >40 no header, >02 extended ID, >01 multiple-write ABYTES BYTE >04 number of address bytes: 3, 4 or 5 SECSZ BYTE >02 sector size. >01 = 256 bytes, >02 = 512 bytes BLOCSZ BYTE >20 number of sectors per block. 16 or 32. CHIPID DATA >0000,>EC98 extra/>A5/vendor/chip EXTID DATA >0021 only 1 byte is used DATA >0000,>0000 reservedThe file then continues with sector data in numerical order, with extra bytes after each sector. Because of these extra bytes, Smartmedia image files are not compatible with other drive image files, such as floppies or IDE hard drives (*.dsk format).
For more details on the USB-SM card check this page.
The drop list in the upper-right corner reports the current status of the controller, and allows you so change it and to trigger special commands by selecting them from the list (commands are activated when the drop-box closes).
The bottom part of the property page displays information pertaining
to the various endpoints. There are sixteen endpoints in total, but only
four at a time can be displayed.
Use the [<] and [>] buttons to navigate to the next/previous
set of 4.
Endpoint #: The endpoint number, from the point of view of the
bus. Note that there are two endpoints 0, one for input (labelled >0, which
receives SETUP and OUTPUT packets from the host), one for output (labelled
0>, which sends IN packets to the host). The remaining endpoints are thus
numbered 1 through E.
In: Indicates that the endpoint answers IN packets by sending
back data to the host, and is thus an output endpoint! I know it's missleading,
but the USB bus is host-centric by design.
Ping-pong: Indicates that the endpoint has a dual stack. Changing
this box will reconfigure all endpoints, loosing any data currently on
the stacks. Inactive is the endpoint has no size.
Isochronous: Indicates a real-time endpoint. Inactive is the
endpoint has no size.
Stack size: The size in bytes of the stack reserved for the
endpoint. If the endpoint has a dual stack, twice this amount is actually
reserved. Only certain values are allowed, depending on whether the endpoint
is isochronous or not. If you enter an illegal value, it will be converted
to the nearest legal value below it. Leaving the box will reconfigure all
endpoints, which will compromise any data currently on stack.
Int enabled: Indicates that handshake packets to/from this endpoint
will trigger interrupts (data packets for isochronous endpoint). In debug
mode, errors and NAK tokens can also trigger interrupts. This box correspond
to a bit in the InterruptEnable register. This box cannot be changed with
the remote system.
Interrupt: Indicates that the endpoint has triggered an interrupt.
This box correspond to a bit in the Interrupt register discussed above.
This box cannot be changed with the remote system (read-only register).
Error code: The contents of the endpoint's error register. Click
the [?] button for an explanation of the content, and possibly to modify
it. These registers cannot be modified on the remote system.
Stalled: Indicates that the endpoint is stalled, and responds
to requests from the host with the STALL token (although an incoming SETUP
token will unstall endpoint 0). This bit and the following ones are part
of the EndpointStatus registers.
Pong full: Indicates that the "pong" stack contains data (this
stack is only used by endpoints that have dual stacks, in alternance with
the "ping" stack). With the remote system, you can only tick that box for
output (i.e. "IN") endpoints (which sends a "validate endpoint" command)
and you can only clear it for input endpoints (which sends a "clear endpoint"
command).
Ping fill: Indicates the the regular "ping" stack contains data.
The "Clear endpoint" command reset this bits, the "Validate endpoint" command
sets it. See above for restrictions with the remote system.
DATA1: Indicates that the token for the next data packet should
be DATA1 (as opposed to DATA0). This box cannot be modified with the remote
system.
Setup ovf: Indicates a setup overflow, i.e. a second SETUP token
has arrived to this endpoint before the previous one was acknowledged.
This box cannot be modified with the remote system.
Setup arrived: Indicates that the endpoint has received a SETUP
token from the host. This box cannot be modified with the remote system.
Use pong: For dual-stack endpoints only, indicates that the
"pong" stack is currently in use. This toggles when you validate or clear
the endpoint. This box cannot be modified with the remote system.
On stack: The number of bytes currenly on stack. This number
is listed in the first two bytes of the stack for assynchronous endpoints.
Isochronous endpoints do not save this value on stack, so the field will
always contain 0 in this case. If an endpoint is not enabled, this field
will contain "N/A". This field is not used with the remote system.
[View] Click this button to view the contents of the endpoint's
stack in a Memory window. This is a trick of the simulation (the hardware
does not allow this): stacks appear at address >5000 when you set the page
number as >5000 (endpoint 0) through >500F (endpoint 14). You can also
view the entire device controller memory by manually setting the page as
>5100. These buttons are inactive with the remote system.
For more details on the USB device controller, see this
page, or the ISP1161 datasheet.
I am also taking requests. This program was mostly written as a tool for myself, to work on the development of the USB card DSRs. But since I've decided to make it available, I am also interested in knowing what feature you think is still missing. For your information, here are several things I am planning for the future:
- Add a source file viewer tool, which can keep track of execution and
show the current address (and possibly set breakpoints) in the source file.
- Allow windows docking, wich windows stretching/shringkig automatically
to cover the entire surface of the application window.
- Complete the emulation of the USB card (host controller missing).
- Emulate the P-Gram and HSGPL cards.
- Include a source file editor with syntax coloring, and a scanning
routine to detect segments, procedure, lables, etc.
- Trace subroutine calls and returns, have a special window to display
call stacking.
- Have a way to call external tools like assemble and linker and automate
the process so that Bug99 may become a real Integrated Development Environment
(IDE).
- Write a procedural cross-assembler, possibly even an object-oriented
one.
Version 1.0 28/8/09
Version 1.1 22/12/09. Added bus window, USB DC page, remote debugging
of emulators.
Version 1.2 10/3/10. Change protocol for external emulators, added
online help, corrected SB bug in simulation.