### Programming

Whether you're writing programs for the TRS-80 or simply wish to dissect existing programs trs80gp has much to offer. As such this section is rather brief on details. Please do get in touch with me if you have questions.

#### Running Programs

Normally on a TRS-80 programs are run either as `/CMD` files at the TRS-DOS prompt or loaded from cassette with CLOAD or SYSTEM commands. This is the best way to test programs you write but only needs to be done as a final test. For development trs80gp will directly load programs from the command line or via the File → Run... menu or via drag and drop. This is largely similar to standard procedure but does has its differences. Existing TRS-80 games often work well when run directly but there's no guarantee.

Files that start with `#!` are considered to be script commands. When given on the command line they operate almost identically to `-ib file` except the commands will be done after all other command-line automated input. The File → Run... menu or dragging and dropping the file will also execute the commands in the script.

#### Batch Mode

Activate batch mode using the `-batch` command line option. In this mode many operations (most in the Record menu) will not prompt for a file name but will instead simple write the file to some fixed file name. This may seem odd but is very useful for testing your programs or trs80gp itself. One way to use this is to have your program write status information to the printer (out $F8 will do on Model 3,4) and use the emulator extensions to make trs80gp exit. You can then run it using:

         trs80gp -m4 -ee program.cmd

And it will go through its paces writing output to `trs80-printer.txt`. If trs80gp doesn't exit then you know your program went wrong.

In batch mode many of the menu entries switch to saving files without prompting. In most cases those files are named in sequence starting with `file-0.txt`, `file-1.txt` and so on. Those are represented by `file-%d.txt`.

Menu | Output file(s)
--- | ---
Bus Use | bus-use-%d.txt
Backtrace | backtrace-%d.txt
Text VRAM | trs80-text-%d.bin
Character Generator VRAM | trs80-char-%d.bin
Graphics VRAM | trs80-graphics-%d.bin
RAM | trs80-ram-%d.bin
RAM16 | trs80-ram16-%d.bin
Expansion RAM | trs80-expram-%d.bin
XLR8er RAM | trs80-xlr8er-ram-%d.bin
Cassette → Auto Save | trs80-cassette-%d.bin
Audio | trs80-%d.wav
MHz Audio | trs80-%d-mhz.wav
CPU Profile | profile-%d.txt
Trace | bus-trace-%d.txt
Flash Video | trs80-%d.flv
Video | trs80-%d.avi
Animated GIF | trs80-%d.gif
Screenshot | trs80-%d.gif
Printer | trs80-printer.txt
Diskette (on exit) | trs80-drive%d-%d.dsk
Hard Drive | trs80-hard-disk-%d.dsk
Wafer (on exit) | trs80-wafer%d-%d.tape

It is worth re-iterating that automated input options are tantamount to scripting control over the emulated TRS-80 and can be used to build up automated tests of your TRS-80 programs.

#### The Z-80 (and other CPUs) Debugger

To keep this section concrete it often refers to the Z-80 debugger. But rest assured there is also full 6800, 6803, 6809 and 68000 debuggers in trs80gp.

The Z-80 debugger may be activated at any time using Debug → Z-80 Debugger... It will also come up automatically when a breakpoint is hit. Breakpoints can be set interactively in the debugger window in the section just below the "Go" button. A breakpoint can be at a single address or cover a range of addresses using "addr1:addr2" syntax. Make sure to tick the checkbox next to the address/label to enable the breakpoint. PC breakpoints can also be toggled by double-clicking a line in the Disassembly sub-window.

You may set up to 4 breakpoints of each type. A "PC Breakpoint" is the traditional kind which is triggered whenever a program executes in the given address range. Other types trigger whenever memory is read or written in the range or I/O is performed. These types are useful to find when particular variables are changed or accessed and finding when devices are accessed.

Breakpoints may also be set on the command line by the `-b`, `-bm`, `-bio` and related options. For Z-80 machines use `-b 0` to start the debugger immediately at machine startup or reset. On 6800, 6803 and 6809 machines use `-bmr fffe` to achieve the same effect.

A `>` appears in the disassembly window to indicate the next instruction to execute and an asterisk (`*`) to show any active PC breakpoints.

Memory and I/O breakpoints show extra information in the debug window when they are triggered. The Disassembly sub-window will show a `!` to indicate the instruction that caused the fault and additional letter codes indicating what kind of fault or faults occurred. The `>` will point to the next instruction to execute as usual.

           R      Read protected memory
           W      Write protected memory
           E      Execute protected memory
           S      Stack protected memory
           I      Input protected I/O
           O      Output protected I/O

The debugger window title will indicate the CPU has stopped, give the memory or I/O address involved and the breakpoint that triggered the stoppage, if any. Programs loaded in `.bds` form come with memory protection and the debugger will show "`.bds file`" as the source of a fault. Or "`program`" if the program itself set up protected memory with emulator extensions.

Various sub-windows show the current Z-80 register contents with them displayed in red if they changed during the previous step. All values are displayed in hexadecimal except for the T-state and cycles counters. There is also a view of the top of the stack and a T-state counter which can be changed as desired to measure intervals interactively.

The Step button moves execution forward a single instruction. Step Over sets a breakpoint after the current instruction and resumes execution. This is useful for `CALL`s to run quickly though a subroutine. Grizzled Z-80 programmers know there's no guarantee a `CALL` will return right after itself so caveat emptor. "Go" resumes execution until the next breakpoint or protection violation. The "Emulator Extensions" checkbox may be turned off to disable protection checks.

When single stepping the display will turn gray to give an indication where the CRT beam is at that moment in execution. There are also boxes in the lower left which give the CRT beam raster Y and X coordinates. The debugger is still operational when the TRS-80 is running. You can change registers and memory locations which will show a light-blue background to indicate you've frozen your view of them so you may change it.

Since the screen shows the contents of the previous frame and the drawing of the current frame you will not usually see an immediate change when writing to screen memory. It only shows up when the CRT beam reads and draws it. The debugger memory view gives you the ability to see immediate changes to the various different RAM systems. The defaults is "Z-80 Memory" which shows the Z-80's view of its 65536 memory locations. In the Model 1 and 3 this will show the BASIC ROM in the first 12 or 14 K or memory, the keyboard matrix from $3800 to $3BFF, the video RAM from $3C00 to $3FFF and ordinary RAM from $4000 up to $FFFF or less if a value lower than 48 was given to the `-mem` command line option. There may be no memory for some of the address space (e.g., $3000 .. $37FF on the Model I). Such regions will display as `~ff` (or `~00` on the Model II) and cannot be changed.

You can also select just the RAM to focus on the 48K of memory. But keep in mind these other views use their own addressing. The RAM view starts at 0 but that is seen (by the Model 1 and 3) as starting at $4000. The amount and type of each varies depending on the Model but you'll typically see Text VRAM for the usual character display, and Hires VRAM for the high resolution graphics option (which is usually only accessible to the Z-80 through I/O ports).

You can search through memory by typing a string into the search box. The usual backslash escapes can be used for control and graphics characters: `\n`, `\r`, `\t` and `\HH` for any hexadecimal value. If the string starts with `$` then the rest is taken to be hexadecimal digits with spaces ignored. The `<` and > buttons cycle through the matches which are highlighted in the memory window below.

In a clunky way RAM can be changed. The easiest approach to to select a memory byte and write a new hexadecimal value for it. The emulator simply reads back the memory dump so you can also delete a line and enter any address followed by a colon and a series of space-separated hexadecimal bytes to change memory locations without having to look at them.

A few pseudo-memory regions are viewable but not changeable. They are intended to give a partial view of the TRS-80 hardware state.

       Z-80 Device        What the Z-80 would return if an I/O were read.
       Z-80 Port Writes   The last value written by the Z-80 to a port.
       Z-80 Port Reads    The last value read from an I/O port by the Z-80.

At the bottom of the window are line of check boxes and drop-downs to control bus tracing which is discussed later.

Most of the Z-80 register state shown is familiar to Z-80 programmers and can be directly altered by Z-80 programs. The `IFF1` checkbox is checked when interrupts are enabled (by an `EI`) instruction and not when they are disabled by a `DI` instruction or entry into an interrupt routine. Relatedly, `IM` shows the interrupt mode of the processor which pretty much has to be 1 for Model 1, 3 and 4 computers and 2 for the Model 2 line. The `I` register is mostly only relevant in interrupt mode 2.

Other state is not directly accessible and pretty much just showing off how accurate trs80gp's Z-80 emulation is.

`WZ` is an internal temporary register used by Z-80 during various 16 bit operations. In an officially undocumented but reliable quirk of implementation bits 3 and 5 of this register are put into bits 3 and 5 of the flag register `F` whenever a `BIT` test is done on `(HL))`. Early investigators of this called the register MEMPTR. Google "Z80 MEMPTR" or try this link to learn more.

`EXX`, `AFAF'`, `DEHL` and `DE'HL'` show the state of internal flip-flops that select different banks of registers when `EXX`, `EX AF,AF'` and `EX DE,HL` instructions are executed. Effectively they show the number of times modulo 2 each instruction has been executed but the Z-80 program and trs80gp's Z-80 debugger show the currently active sets are you would expect.

The dropdown shows special Z-80 processor states and will spend 99.999% of its time in `Normal` mode. The other modes are:

- IntrDis - An `EI` instruction was just executed so the Z-80 will not respond to a maskable interrupt until the next instruction finishes execution.
- Halt - The Z-80 has executed a `HALT` instruction and will not resume execution until an interrupt occurs. During this time it will continue to fetch and ignore the opcode of the current instruction.
- Pfix, PfIy - The Z-80 is in the middle of a series of `$DD` and `$FD` bytes. The Z-80 only pays attention to the last byte in such a series to determine if it has an `IX` ($DD) or `IY` ($FD) instruction. The Z-80 cannot be interrupted during this processing but for practical reasons trs80gp breaks such sequences down to a progression of artificial `pfix` and `pfiy` instructions.
- PostIff2 - The Z-80 has just executed a `LD A,I` or `LD A,R` instruction which will read the wrong value of `IFF2` if an interrupt occurs at the same time as the instruction. This is to emulate a Z-80 bug and, unlike the others, does not correspond to a real internal state latch.

The debugger also provides a sub-window for watching expressions. For each expression you choose what result to show: The memory byte or word at the calculated value, or the value itself (or the high/or low byte of the value)

Expressions use C-like syntax consisting of:

- Decimal constants (use `$` or `0x` to prefix hexadecimal constants)
- Parenthesis to control order of evaluation
- C number operations: `+ - * / %`
- C bit operations: `! ~ << >> & ^ |`
- C comparisons: `== != < > <= >=`
- C logical and/or: `&& ||`
- Register names: e.g. `A B C AF HL IX AF'`
- Register flags: e.g. `F.C, F.N`
- Source code symbol values (if loaded)

There is a special syntax for reading memory inside an expression. The expressions `(expr)b` and `(expr)w` return the value of the byte or word at the memory location inside the expression.

#### Source Level Debugging

My zmac cross assembler will output machine language programs in `.bds` format. It is a text format so by looking at it and the zmac source code you can probably figure out how to generate it yourself. But the important part here is that loading `.bds` files from the command line will enable source level debugging.

Use Debug → Source Code to bring up the source code that has been loaded. It will look a bit like an assembler listing file. The current program location will be highlighted and follow the execution of the Z-80.

The format also defines symbolic labels so you can type these labels in to the breakpoint or register windows instead of having to look up the hexadecimal values yourself. You can also use labels for the `-b` and other command line option to set breakpoints.

In certain situations you may want to have symbols available for a program but don't wish to load it into memory. The `-ls` command line option and File → Load Symbols... menu entry are used to only load the symbols from a `.bds` file. Doing so allows you to use symbolic names in the debugger but does not alter RAM contents in case the program is already underway.

Some models have built-in symbols and source code which are automatically loaded. While often helpful this sometimes gets in the way of debugging programs. Use the `-nrs` option or File → Unload Symbols to stop this. Though "Unload Symbols" will drop any other symbols or source code you have loaded.

trs80gp also uses the memory protection information in `.bds` files to trigger breakpoints if your program attempts to overwrite itself, read program memory or execute data. If the program runs out of control it will at least trigger a breakpoint before it has destroyed itself making it easier to recognize and track down the problem.

This can get in the way if your program intentionally modifies itself. For example, this oode saves `HL` to an `HL` load instruction.

              org   $8000
       start: ld    (save+1),hl
              ; ... use HL but just a NOP for now
              nop
       save:  ld    hl,0
              jr    $
              end   start

Running the `.bds` version of the program will cause it to stop at the `NOP` because the previous instruction tried to write to its code. You can work around this problem by checking and unchecking the "Emulator Extensions" in the debugger window. It has the side effect of disabling the `.bds` memory protection.

The proper fix is to tell zmac that the last two bytes of the of the `ld hl,0` instruction can be treated as data. The idiom for this is to assemble both code and data at that location:

              org   $8000
       start: ld    (save),hl
              nop
              ld    hl,0
              org   $-2
       save:  defw  0
              jr    $
              end   start

The makes the code is a bit better. There isn't a magic `+1` added to `save`. When looking at `save` the use of self-modifying code is explicit. Though obvious in this simple example it would not be apparent in large program.

#### Disk Viewer

Under the Debug menu there is a Disk Viewer which allows you to browse through all the floppy and hard drive images inserted and examine their data. There is a search feature to look for strings or binary data. The usual backslash escapes can be used for control and graphics characters: `\n`, `\r`, `\t` and `\HH` for any hexadecimal value. If the string starts with `$` then the rest is taken to be hexadecimal digits with spaces ignored. The `<` and `>` buttons will cycle through all the matches.

Use the drop downs to select disk images, sides, tracks and sectors. The sector dropdown presents both the physical and logical sector numbers. The logical number is the value written on the disk and is what is used when we generically refer to reading or writing sector N. The physical number is the relative position of the sector in the track.

#### Device Map

The debug menu also features the somewhat experimental "Device Map" feature. It gives you a quick overview of the current mappings of Z-80 address and I/O space to RAM and devices. In short, something like the typical memory map seen in programmer guides. Do keep in mind that it shows the mapping when it was brought up. If the program subsequently switches memory maps the window will not be updated.

The feature is experimental mainly because it doesn't yet display all the emulator implicitly knows about the address space. For example, the Model I does not have any memory mapped from $3000 to $36FF but the map will display that as read-only RAM. And it says nothing at all about the memory mapped printer and floppy disk devices accessible in the $3700 - $37FF range. In other words, the map can be incomplete or misleading. But it seems more handy having it around even with its current shortcomings.

#### Advanced Recording

Sometimes examining memory in the debugger is too cumbersome. The "Text VRAM", "Graphics VRAM", "RAM", "RAM16" and "Expansion RAM" entries in the "Record" menu will save those RAM areas to a file where you can use external tools to do a more thorough analysis.

The normal recording options can assist debugging. It may be helpful to step through a video a frame at a time to see some graphical glitch in detail. The "MHz Audio" option takes this to the extreme by recording audio output a sample rate equal to the speed of the Z-80. In effect this lets you see exactly when the audio changes.

The Trace option is the most useful so I've dedicated section to it. The other options attempt to self-document in their output. Unlike the Trace option these other options don't record everything. Typically they'll just track the PC values to keep overhead low. When they do their final output the use whatever value is in RAM at the time for the disassembly. If the program changes you may seen confusing output. This gets even worse if the memory mapping changes.

All these recording options can be activated and stopped at any time. It is useful and often desirable to start them when the program is stopped in the debugger and then stop them at the next breakpoint after an interesting subroutine or full step of a game simulation has run.

Record → Z-80 Profile tracks every instruction executed and shows you a list of those instructions, the number of times each instruction was executed and the total T-States spent on each instruction. It is intended to help measure where your program spends its time to be used as a guide for optimization. It can also be used to simply track what a program as done during an interval. However, "Bus Use" is better for that task and Trace will show every instruction in order.

Record → Backtrace show the last 65536 instructions executed. In theory you can use this to respond to a crash. But practically speaking that many instructions is at most a tenth of a second so you're not likely to be quick enough to catch it.

Record → Bus Use tracks the execution of a program. The output is much like a disassembler but with markup indicating how memory was accessed: read, written, executed, jumped to, called and so on. The disassembly tends to be better than a static disassembly since it uses the Z-80's execution path to point out what is code and what is data.

The disassembly will be entirely commented out except for any areas where a program was loaded by the command line (or using File → Load/Run) into memory. The intent here is to distinguish the loaded program from the ROM or operating system routines it uses. If the program is sufficiently put through its paces the result should be a good disassembly that can be assembled to produce the original code. Unlike the other trace options any data uncommented in the disassembly is based on the original data loaded so it won't be fooled by simple self-modifying code. However, this is a problem if the program relocates itself. In which case you'll have to get a relocated version of the program loaded. At least "Bus Use" will help understand the relocator code.

#### Emulator Extensions

These are enabled by the `-ee` command line option. They can be turned off using the "Emulator Extensions" checkbox in the Z-80 Debugger. A Z-80 program accesses them by sending a function code to I/O port $47. Here is a brief overview:

         0     Set bus permissions for address HL to DE to B
         2     Trigger bus fault B
         3     Disable (B=0) or enable (B=1) bus permissions
         4     Trigger execute fault (i.e., drop into the debugger)
         5     Reset (B=0) or get (B=1, into DEHL) T-state counter
         6     Control recording
                  B=$41 - toggle audio recording
                  B=$4D - toggle Mhz Audio recording
                  B=$47 - toggle animated GIF recording
                  B=$46 - toggle Flash video recording
                  B=$56 - toggle video recording
                  B=$53 - take screenshot
                  B=$47 - take cleanshot
       64..127 Set parameter (see below)
         128   exit emulator with return code BC
         255   set carry flag (to detect if extensions active)

Function 5 allows for automated profiling of Z-80 code. Function 128 is typically used to end a test in batch mode. The bus permissions are very helpful in tracking down nasty bugs. For example, you can set your code section to execute-only. The emulator will trap into the debugger the instant something tries to overwrite over your code. Or even read it. Another useful technique is turning off stack permissions at the bottom and top of your stack to detect stack overflow or underflow.

For function 0 the lower 7 bits in B are set to indicate what Z-80 operation is allowed on that memory location. Or for the first 256 addresses what I/O operation is allowed on a port. Those bits are:

       Mask    Operation  Z-80 Debugger letter indicator
         1     Read       R
         2     Write      W
         4     Execute    E
         8     Stack      S
         16    In         I
         32    Out        O
         64    DMA        D

Stack permission is required for CALL, RET, PUSH, POP, RETI and RETN.

##### Using Emulator Extensions in BASIC

For BASIC where `OUT` is readily available but setting register contents is difficult there a way to trigger any function with just OUT commands.

`OUT 71,32+n` will trigger function `n` using whatever parameters were previously set. A parameter is set by first doing an `OUT 71,64+p` where `p` is the parameter number and then doing `OUT 71,x` to set the value. If a command requires a register then the parameter triggered version of the command will read parameter 2 for register B, parameter 3 for register C, parameter 8 for H and so on. Or put another way, you select the parameter for register R by sending the ascii value of the register letter.

For example, this will toggle animated GIF recording:

        OUT 71,66:OUT 71,71:OUT 71,32+6

`INP(71)` is used to get results from emulator extensions. Only detection (code 255) and T-state counter read (code 7, B=1) return results. Here is a simple Model III example that checks the emulator extensions are installed. If so, it then reads the number of T-States to execute the little `FOR` loop and shows them as a raw value and translated to milliseconds.

    10 OUT 71,255:IF INP(71)<>1 THEN ?"You forgot -ee":END
    20 OUT 71,66:OUT 71,0:OUT 71,37
    30 FOR I=1 TO 10:NEXT
    40 OUT 71,66:OUT 71,1:OUT 71,37
    50 T=0:FOR I=0 TO 3:T=T*256:T=T+INP(71):NEXT
    60 ?T;"T states";T/2027.52;"ms"

#### Bus Trace

The Record → Trace feature is a very powerful and comprehensive tool for debugging Z-80 programs and the emulator itself. It can log every instruction executed, memory access, interrupt and I/O port access the Z-80 or any DMA device does. It also places markers in the output file to indicate when a frame has ended and when one second of execution has finished. It can be activated a program start with the `-trace` option. The full log is recorded in the output file. The last frame or two of the log can be viewed using Debug → Trace Log...

The output can be voluminous. You'll want to use breakpoints to turn tracing on and off for as short a period as possible. The "Tracing" checkpoint in the Z-80 Debugger is a convenient shortcut. And there are additional check boxes to enable or disable tracing for Z-80 instruction, I/O accesses, memory accesses and interrupts.

For even finer control I/O logging can be enabled on a per-device basis. This is handled by the device drop-down. The interface is awkward. As you select each device in the drop-down the checkmark to the right changes to indicate if that device is being logged. But you still must check the I/O box to enable I/O logging. To make it more confusing but usable the best course is to turn I/O off, select the device you're interested in, enable it and then turn I/O back on. If you turn I/O on first it will enable all devices by default.

Yes, it's bad but at least it gives some way to target particular devices. Obviously these controls should be in some other window but the debugger happened to be handy at the time. trs80gp wasn't built in a day.

The actual logging looks something like this:

       8033317 @3018 z ex       jp     $35c2
       8033327 @35c2 z ex       push   af
           +11 @35c2 z wr _ffb4 00 ram[ffb4]
           +11 @35c2 z wr _ffb3 44 ram[ffb3]
       8033338 @35c3 z ex       in     a,($e0)
           +11 @35c3 z in _e0 fb
       8033349 @35c5 z ex       rra
       8033353 @35c6 z ex       jp     nc,$3365
       8033363 @35c9 z ex       rra
       8033367 @35ca z ex       jp     nc,$3369
       8033377 @35cd z ex       push   bc
           +11 @35cd z wr _ffb2 38 ram[ffb2]
           +11 @35cd z wr _ffb1 80 ram[ffb1]

The first column is the T-State counter. The second is the PC of the Z-80 when the operation occurred. Next a letter code shows the device responsible ('z' for Z-80 and 'd' for DMA chip). The type of access follows. Most are "ex" for instruction execution with a disassembly of the instruction following. But for reads, writes, ins and outs (rd, wr, in, ot) the memory or I/O address is shown followed by the value read or written. Other possible operations are:

         ht     Fetch during Z-80 halt
         i0     Interrupt mode 0 bus read
         i1     Interrupt mode 1 bus read
         i2     Interrupt mode 2 bus read
         ni     NMI (non-maskable interrupt) bus read

After any access there may be a description of what the value means to that device and possibly the internal state of the device. A good example is the CRTC video controller chip used in the Model 2 and 4. An I/O write (out) to its address register will be annotated with the name of the register selected. An I/O write will show the name of the register changed and its current value. Some devices are very simple in that any byte read or written can only have one meaning. But for the CRTC a write to a register depends on which register was previously selected. Without the annotation you would have to search backwards for the last register selection. And if the register is 16 bits wide you'd also have to look back for the last time that other 8 bits were changed. This is tedious and may not even appear in the bus trace you've made.

Not all devices provide annotations. If they do then you can bet they were giving us trouble in developing the emulator. Most of the Model 2 devices have annotations.

By the way, the underscore and @ signs in front of addresses are intentional and useful. vi (and maybe other editors) make it easy to search on words. So starting a search on _ffb2 will only find other references to that memory location being read or written. But searching the word ffb2 will find instructions that reference the address. Or you can search for @ffb2 explicitly to restrict your search to only instructions executed at that address.