SIG/M VOLUME 6

6502 SIMULATOR - REFERENCE DR. DOBBS 8/80
6502 ZAPPLE MONITOR

       SIZE    NAME            CONTENTS

               -CATALOG.006    CONTENTS OF SIG/M VOL. 6
               ABSTRACT.006    DESCRIPTION OF EACH MODULE
                               IN THE 6502 SIMULATOR

6.1     11K     ZILASM.COM      6502 SIMULATOR
6.2      5K     ZX65.COM
6.3     98K     ZX65R.PRN
6.4     39K     ZX65R.ZSM
6.5     15K     ZXART.DOC
6.6      9K     ZXHINTS.DOC
6.7     23K     ZXLDR.PRN
6.8      7K     ZXLDR.ZSM
6.9      1K     ZXTAB1.DOC
6.10     1K     ZXTAB2.DOC
6.11     1K     ZXTAB3.DOC
6.12     1K     ZXTAB4.DOC
6.13     2K     CONCOD.LIB      CONTROL CODES FOR 6502 ZAPPLE
6.14     1K     ZAPMON.MOS      ZAPPLE MONITOR FOR 6502
6.15     5K     ZAPMON.HEX
6.16    11K     ZAP3.INS
6.17     3K     ZAP5.INS
6.18     3K     ZAP1.INS

       This disk contains the following files, as described briefly
here:


1:      ZXART.DOC  This is the original text of the article which app-
       eared in the August, 1980 edition of Dr. Dobb's Journal.

2:      ZXTABx.DOC  These tables are also part of the text for the ar-
       ticle.  ** NOTE:  Where addresses appear in these tables, they
       pertain to a 32K byte system with standard 512 byte CBIOS. For
       any other size system loaded just below CBIOS as described, the
       first two digits of these addresses will be {CBIOS page minus
       four}. I.E. for standard 32K, CBIOS page is 7EH. Subtract four
       and the result is 7AH.

3:      ZXHINTS.DOC  A little additional useful information on loading
       and running ZX65.

4:      ZX65R.ZSM  The Z80 source code for the interpreter. Version 2.1
       is relocatable and must be linked with ZXLDR following assembly.

5:      ZXLDR.ZSM  Source code for the system 'booter.' CP/M loads ZX65R
       normally into the bottom of the TPA at 100H. ZXLDR finds CBIOS,
       calculates and inserts the relocation offsets, and then boots
       ZX65 up to high memory and jumps to it.  Version 2.1 must be lin-
       ked with ZX65R following assembly for this to work.

6:      ZX65R/XX.PRN and ZXLDR/XX.PRN  This is the listing output of the
       assembler, showing system memory locations PRIOR TO RELOCATION.

7:      ZX65.COM  Getting down to business...you should be able to
       run this file immediately simply by typing 'ZX65' to the
       CP/M prompt.
ZX65: Simulating a Micro                                        Page 1


       Having logged many hours of software development work on my Z80-
based system, I recently decided that I was up to a particular challenge:
using my system as a development tool for a totally different microprocessor;
specifically, the 6502.  This decision, I must confess, was not altogether
based on a burning lust for knowledge, but rather on a more practical re-
quirement:  I had become involved in the development of a 6502-based device,
and had no ready access to a 6502 development system.  I decided that a sim-
ple cross-assembler wasn't good enough, and set out to write a 6502-to-Z80
object code translator/simulator/interpreter.

       The program described here, which I have dubbed ZX65, is the result
of my efforts to generate a software package to perform this task.  It is
useful not only for the intended purpose of software development, but also
for the rewarding experience of exploring a whole new field of good soft-
ware written for a processor other than one's own.

       ZX65 operates as an interpretive simulator; that is, a simulated
6502 CPU is maintained in system memory, and each encountered 6502 instru-
ction is decoded and processed interpreter-fashion to properly act upon the
simulated CPU registers.  The entire package resides in just over 4K Bytes
of high system memory, leaving the remaining portion, including the all-im-
portant (for 6502) base page, free for program and data storage.



ZX65: Simulating a Micro                                        Page 2


Note that CP/M* serves only as a loader and is not used thereafter.  In fact,
while the program loads normally into CP/M's Transient Program Area, it imm-
ediately relocates itself into high memory, overlaying both the CCP and the
BDOS portions of CP/M.  The user I/O linkages (CBIOS), however, remain intact
and are used by the package to perform disk and console functions.  The func-
tions which must be provided by the system are a subset of those required by
CP/M and should thus be readily available.  These functions are all accessed
via a jump table within the interpreter and thus can be readily changed to
accomodate different system requirements (see table 1).  Parameters must be
passed to the drivers in register "C" (register pair "BC" for item six) and
data, if any, is returned in the accumulator.

       ZX65 is referred to as a package since it includes three distinct
function groups.  The first and largest is the interpreter/simulator itself.
The second group is an elementary monitor providing the functions of memory
examine and modify.  The third group consists of a self contained, elementary
disk operating system (DOS). (Note: ZX65 files are not CP/M compatible.) The
normal configuration assumes a two-drive system, with the system diskette on
drive A, and all internal disk access routed to drive B.



ZX65: Simulating a Micro                                        Page 3


(Modification for a single drive system could easily be done, requiring the
user to switch diskettes after the package is loaded.)  The package is writ-
ten in standard Zilog/Mostek source code and is quite heavily commented.  Much
use is made of the Z80's special instructions and index registers, and oper-
ation on an 8080 is definitely not possible without extensive modification.
Although the commented listing should guide you through the program's opera-
tion without too much trouble, a brief description of the interpreter portion
is in order. A study of the small but powerful instruction set of the 6502
will reveal certain patterns in the op codes, as also occurs with most other
processors. The eight "BRANCH ON CONDITION" codes, for example, all have zero
as a low-order nybble, while the high-order portion is always an odd value.
Another pattern, not so obvious, is that every instruction having an odd-
valued op code uses multiple addressing modes.  These and other such patterns
are exploited by the program.  Even so, much of the code is devoted solely to
decoding the op code and transferring control to the proper instruction proc-
essor.  The code beginning at "STEP" (line 241) performs the initial decoding,
and fully decodes certain instructions such as "RTI", "JMP", and a few others.
In most cases, decoding proceeds to the point where the instruction is known
to be part of a group, such as the branch group described above.  In these
cases, look-up tables are used, but not always in the same way.



ZX65: Simulating a Micro                                        Page 4


The branch group and the flag set/reset group, for example, derive mask
patterns from the tables which are used for testing, setting, or resetting
the condition flags.  In the case of multiple addressing mode instructions,
however, the tables serve an entirely different purpose.  The table contents
are, in these instances, decoded into addresses for indirect jumps; first to
the addressing mode processors, and then to the actual instruction processors.
Each processor performs its instruction as required.  The "ADC" instruction,
as an example, causes a byte of data to be fetched from memory or from the
object code, depending on the addressing mode.  After setting the Z80 carry
flag to match the simulated 6502 carry flag, the data byte is added to the
value currently in the simulated accumulator, and the result is stored there.
The simulated carry flag is then updated to again match the Z80 carry, and the
simulated sign, overflow, and zero flags are set or reset according to the re-
sults in the accumulator.  (In this case, the overflow flag is set or reset
according to a logical "OR" of bits six and seven.)  Considerable care has
been given to treatment of the flags, since Z80 flags and their 6502 name-
sakes do not always have the same meaning.  (Case in point:  the 6502 carry
flag assumes a logical "NOT" borrow meaning during subtract and compare op-
erations, while the Z80 and most other common processors invert the carry
flag internally during these operations so that it represents a "TRUE" bor-
row. Other flag differences, for the most part, are more subtle.)



ZX65: Simulating a Micro                                        Page 5


Finally each individual processor is responsible for exiting with codes
for the mnemonic, the addressing mode, and the number of bytes occupied by
the instruction available for use by the "DISPLAY" routine (line 173) to in-
dex into yet another set of tables and retrieve the ASCII messages for mnem-
onic and addressing modes.  Upon exiting the instruction processors, the val-
ue stored in "NEXT PROGRAM COUNTER" is updated, and control is passed back to
the COMMAND section where the operating mode in effect determines whether to
display the updated CPU contents, and whether or not to continue execution
with the next instruction.



       Several distinct operating modes are available, defined briefly as
follows:

SINGLE-STEP MODE:  One instruction is decoded and executed. The console
       then displays the address of the instruction just executed (Current
       Program Counter), the decoded instruction (Mnemonic and Operand),
       the state of all CPU registers, and the address of the next instr-
       uction to be executed (Next Program Counter).  Control is then
       returned to the user.

MULTI-STEP TRACE MODE:  The user specifies up to 255 instructions to be
       executed with the results displayed as above following each step.
       This occurs at the rate of approximately two instructions per sec-
       ond.  Control is returned to the user after the required number
       of steps have been executed and displayed.

RUN-TO-BREAKPOINT MODE:  Instructions are executed without display up to
       and including the user-specified breakpoint.  CPU registers are
       then displayed as above, and control is returned to the user.



ZX65: Simulating a Micro                                        Page 7


FREE-RUN MODE:  Instructions are executed with no display and no break-
       points.  The console keyboard, however, is monitored, and CPU con-
       tents are displayed as above and control is returned to the user
       at any point upon console input.

       The user may examine any or all CPU registers, including the Pro-
gram Counter, at any time that he has control, without otherwise disturbing
any operation on progress.

       The 6502 "BRK" instruction (software interrupt) is handled through
a vector location, just as in a normal system.  Optionally, however, the BRK
instruction may be used (and is initialized) to return control to the user
in the same manner as the breakpoint mode described above.  The BRK instru-
ction and breakpoint mode operate independently, and both may be used in the
same program.  Additionally, up to five different "user" subroutines may be
called for transfer of control to Z80 routines (such as console I/O).  These
are invoked by executing either a "JMP" or "JSR" instruction to addresses
0000, 0001, 0002, 0003, and 0004 (HEX).  Control is passed via a jump table
located within the interpreter, which the user may load with Z80 "JP" ins-
tructions to the desired subroutines.  The subroutines must be terminated
in the normal Z80 fashion by one of the "RET" instructions.  Note that the
first two entries in the table (JMP or JSR 0000, 0001 HEX) are initialized
as console input and output via the 6502 accumulator.  Three parameters may
be passed to and from all user subroutines, as outlined in table 2.  Table
3 lists the locations of the BRK vector and the user subroutine jump table.



ZX65: Simulating a Micro                                        Page 8


       Although the interpreter is quite versatile and all 6502 instruc-
tions are handled properly, there are some limitations to its use.  Perhaps
the most important of these is that, even in the "free-run" mode, execution
is quite slow compared to an actual 6502 running at normal clock speeds.  No
attempt has been made to correlate execution times with normal 6502 clock
periods.  (This may, in fact, be impossible due to the way in which the sys-
tem handles multiple addressing modes.)  Therefore, programs incorporating
software timing loops will not execute properly.  Also, since the package was
intended for software development, hardware interrupts are not supported, and
only a limited amount of hardware interfacing can be performed through the
"user" subroutine calls.

       Two program listings are included here.  The first, called "ZXLD",
is a short program whose only function is to boot the main program from the
CP/M Transient Program Area to high memory.  The second listing is the in-
terpreter itself, assembled to reside from 6F00 to 7DFF (HEX) in a 32K sys-
tem.  Note that this leaves 512 bytes, normally containing CBIOS, unaffected.



ZX65: Simulating a Micro                                        Page 9


The program is not relecatable, so that in order to run in a different mem-
ory configuration, it will be necessary to reassemble the source with a new
value in the "SIZE EQU XX" statement.  All other addresses are derived from
this value.  If the object code is to be manually loaded for the 32K system
then "ZXLD" must be loaded first, starting at 0100 (HEX).  Then start loading
ZX65 at 0110 (HEX), continuing until the end.  Finally, use the CP/M "SAVE"
command (SAVE 15 ZX65.COM) to write the object code to disk.  The package can
now be invoked by answering "ZX65" to the CP/M prompt.  If you are reassem-
bling the package, then you should also reassemble the ZXLD routine (modified
for your system) so that you have a .HEX file for each module.  Then load
the package using DDT as follows:

       DDT ZXLD.HEX
       IZX65.HEX
       Rdisp

where "disp" is the load offset value required to load the object code from
the .HEX file at a different address than that specified.  (DDT will calcu-
late "disp" for you if you type "H110,ssss", where "ssss" is the actual
starting address of your program.  DDT will respond with the sum and diff-
erence of the two values, and the difference will be the required value
"disp".)  Finally, save the object code as directed above for manual loading.



ZX65: Simulating a Micro                                        Page 10


       To run the program, place the disk with ZX65.COM on drive A (this
disk should also have a copy of CP/M so that the system can be restarted, if
necessary, without changing disks.)  Place the ZX65 data disk on drive B.
Start CP/M and invoke ZX65 by answering "ZX65" to the CP/M input prompt.
The system will prompt you with a header and a ">" symbol.  You are now in
the command mode, and typing one of the command codes (see table 4) will
cause the appropriate action to occur.  Note that if you are using a disk
not previously used for ZX65 on drive B, you will be unable to use the ZX65
DOS functions until you have initialized the disk.  This is done simply by
typing "I", at which point the system will ask you to verify this request
with a "Y" or "N".  The reason for this (note this well) is that the "I"
command clears and initializes the directory on disk B.  This is the equiv-
alent of the CP/M command "ERA *.*" and must be used with caution.

       For those unwilling to type in a 4K byte program by hand, I will
make the package available on a standard 8 inch IBM format, single side,
single density diskette (Sorry, I can't handle any other format!) at a nom-
inal charge of $15 to cover time and material.  Write to me at the address
given at the head of this article, and specify your system memory size.  I
will send a diskette containing both source and object files assembled to
reside in high memory as described above, as well as a copy of ZXLD.



ZX65: Simulating a Micro                                        Page 11


A command summary, operating hints, and other general information will be in-
cluded on the disk.

       Finally, although this program has been rather exhaustively tested
with a variety of 6502 software (both simple and sophisticated) I cannot
guarantee it bug-free.  I have included no copyright notices of any kind,
and I hope users will feel free to copy, add, delete, and improve at will.
(I would like to hear of any major modifications...I may want to include them
myself!)  As stated at the outset, the package was developed as a side benefit
of another project, not as a money maker, and if anyone else finds it useful,
so much th
e better.                               -RMK



Acknowledgements:

       *CP/M is a registered trademark of Digital Research, Pacific
       Grove, CA.

       While not specifically mentioned in the text, I have relied
       heavily on the information contained in the book "6502 Assembly
       Language Programming" by Lance A. Leventhal (Osborne/McGraw Hill
       Inc., 1979)



*****   Notes on ZX65R v 2.1 and ZXLDR v 2.1    9/80    RMK

       The ZX65R program and source listings on this disk represent a
substantial improvement over those published in DDJ #47.  The 'R' in the
program names means 'relocatable', and that means that the same ZX65
COM file will now run on any size CP/M machine (except Heath/Zenith,
TRS80, and any others using odd memory configurations).  This has been
accomplished mainly through a new loader, ZXLDR.  This loader contains
a complete relocation map for ZX65R.  It finds your CBIOS by examining
the warm start vector at 0001H.  It then insinuates ZX65 just below CBIOS,
after first calculating and inserting new values for all non-relocatable
operands in the 'prototype' ZX65R code.  The loader and the main program
appear as two separate source modules which have been concatenated using
a linking loader, resulting in the run-able ZX65.COM file.  To run the
program, transfer ZX65.COM onto a CP/M system disk using PIP.  Boot up
this disk in drive A, and place a blank disk that you want to use for
6502 programs and data in drive B.  Type 'ZX65'.  Drive B will operate
briefly and the ZX65 prompt will appear on the console.  You are now in
ZX65's command mode.  Refer to the Dobb's article or file ZXTAB1.DOC for
a command summary.

       If you compare the source code for ZX65R with that published
in DDJ, you will notice what appear to be substantial differences in the
listing.  The most obvious change is in the header comments and the 'eq-
uates' which set up memory locations for the system. Even though this
looks quite a bit different, it is for the benefit of relocatability and
has no effect on the operation of the program once it is loaded.  If you
will look a little further and compare the actual instructions, you will
see that they are mostly unchanged.  There are two exceptions. The first
involves the code from line 339 to line 428. These are the instruction
processors for JMP, JSR, RTS, and RTI, and the new code corrects for im-
proper stack handling in the original version. The second change is down
near the end of the code in the console I/O handler. A patch there accom-
odates a few BIOS console output routines which do not return with the
output character still in the accumulator.

       Notice that the memory locations for the USER subroutine link-
ages shown in Table 3 apply only after loading is complete.  To insert
your own subroutine addresses, the best method is to load ZX65.COM under
DDT. You will then find the USER jump table at the following locations:

       USR0            0FCCH *         * The first two locations are
       USR1            0FCFH *         initialized to console I/O and
       USR2            0FD2H           will be relocated during load-
       USR3            0FD5H           ing. The last three will not
       USR4            0FD8H           be relocated.

You may also wish to change the 16-bit 'BRK' vector:

       BRK VECTOR      0FDBH           Not relocated during loading.

Once you have inserted the desired changes under DDT, you may either ex-
ecute the program directly by typing G100, or save it to disk following
warm start with the command 'SAVE 20 ZX65.COM'.


       CP/M COMPATABILITY: As of this writing, I have not yet succum-
bed to Digital Research's efforts to get me to buy the new CP/M 2. From
what I have been able to figure out, it offers very little to me in the
way of advantages. Suffice it to say that ZX65 was written and debugged
using V 1.4, and I cannot say whether or not it will run under any other
version. (My guess is that it will work with V 1.3, but not v 2.X.) The
main reason for any incompatibility will probably have to do with the
fact that my self-contained mini DOS operates the disks and console dir-
ectly through CBIOS rather than by using calls to BDOS which is the more
conventional method. (There is a good reason for this madness which I
will explain shortly.) In any event, since you have spent your hard-
earned nickels for this copy, I suspect that you are resourceful enough
to overcome such problems and implement any necessary patches. If you
do come up with a running version patched for CP/M 2 or for some other
disk format (i.e. North Star etc.), how about submitting it for possible
publication in Dobb's? (No, I'm not on their payroll, but they are re-
ceptive to this type of material and lots of 'hard core' dedicated
computerists read their mag.)

       SOME NITTY-GRITTY: As promised, here is the explanation of why
I have interfaced through CBIOS rather than using BDOS: If you have
done any work at all with the 6502 processor, you will recall that page
zero of memory (0000H to 00FFH) is sacred to it. There are short forms
of many instructions for use on page zero, and the very powerful indirect
indexing modes always use page zero. Now ZX65 by design uses no memory
mapping at all...that is, if your 6502 program is ORG'd at 2000H, that
is exactly where you will load it. (This is in contrast to at least one
TRS80-based simulator that I know of.) Having gone this far, it is only
reasonable to expect that page zero will be totally available to the
6502 program. As you have probably realized by now, the catch here is
that BDOS also likes page zero, and uses large chunks of it during disk
accesses. With one possible limitation (which I will discuss in a bit)
ZX65 totally removes the host system from page zero...even the vectors
at the bottom of memory need not be saved.  ZX65 is, in fact, confined
to the top 1100H bytes of user memory (more if your CBIOS is longer than
512 bytes), and ALL space below that is available for 6502 programs and
data. The one possible conflict that I mentioned is system-dependent,
and may or may not apply in your case. CP/M V 1.4 has a reserved 'scr-
atch' area of 16 bytes located from 0040H to 004FH. Some disk controllers
use this area for temporary data storage during all disk transfers, whe-
ther initiated by CP/M or not. If this is true of your controller, then
you have very little choice but to accept the fact that this portion of
page zero will be messed up whenever you do a disk access from ZX65.
There is still one alternative (I know because I did it!): you may be
able to move this scratch area out of page zero into high memory. Even
if you have this conflict, 6502 programs that use page zero only for
temporary data storage will probably run normally unless the 6502 pro-
gram itself accesses the disk. (Yes, it is possible, using the 'system'
subroutine calls.)

       ZXDOS COMMENTS: Having destroyed BDOS as described above, I was
obliged to include an embedded disk operating system in ZX65. Now, ZXDOS
will never win any awards for versatility, but it is, I think, adequate
for the application. All internal disk access is confined to drive B (a
two drive system is assumed). ZXDOS files are not CP/M compatible. A dir-
ectory is maintained on track zero, and the remainder of the disk is
available for program/data storage. Each directory entry is 16 bytes long,
and contains the file name (format same as CP/M but file type has no spe-
cial meaning), the load address, the disk location, the number of sectors,
and an active/dead flag byte. During a directory display or search, the
directory is paged through a buffer within ZX65 one sector at a time,
continuing until an 'end of directory' mark is located. Files are stored
sequentially and on sequential sectors (no interleaving). A new file will
normally be appended at the tail end of existing files, unless the entire
file will fit into the space allocated for a dead file. Thus a rudimentary
form of dynamic disk space allocation is used, but a full disk will still
contain quite a few empty slots. Killing a file does not actually erase
anything, but simply resets the active status flag in the directory for
that entry. The 'initialize' command writes a properly formatted empty
directory to the disk.

       Finally, it is be possible to use ZX65 with only one drive. To
implement this, load ZX65.COM using DDT, and change the value at address
484H from '01' to '00'.  Save the modified code back to a system disk
following warm start using a 'SAVE 20 ZX65.COM' command. To operate in
this mode, first start ZX65, then immediately remove the system disk
and insert the ZX65 data disk.  From this point operation will be the
same. This works because once loaded, ZX65 does not itself require any
further disk access.

       CONCLUSION: Have fun with ZX65!         -RMK


ZX65: Simulating a Micro                                        Page T1


                               *** TABLE 1 ***

       Functions which ZX65 requires of the host system, and their
       locations within the interpreter.
       -----------------------------------------------------------

       FUNCTION                                        ADDRESS
       --------                                        -------

1.      Test console input status --------------------- 7A2EH

2.      Get single character from console ------------- 7A2BH

3.      Send single character to console -------------- 7A28H

4.      Select disk drive (A or B) -------------------- 7A34H

5.      Home R/W head of selected drive --------------- 7A31H

6.      Set disk transfer buffer address -------------- 7A3DH

7.      Set sector number for next disk access -------- 7A37H

8.      Set track number for next disk access --------- 7A3AH

9.      Read one sector from selected drive ----------- 7A40H

10.     Write one sector to selected drive ------------ 7A43H







ZX65: Simulating a Micro                                        Page T2


                               *** TABLE 2 ***

       6502/Z80 parameter passing to/from user subroutines.
       ----------------------------------------------------


               6502 Register   Passed as       Z80 Register
               -------------                   ------------

               Accumulator ------------------- Accumulator

               X Index ----------------------- B Register

               Y Index ----------------------- C Register




ZX65: Simulating a Micro                                        Page T3

                               *** TABLE 3 ***


       Locations for "BRK" vector and user subroutine table.
       -----------------------------------------------------

       Description             Address of vector/jump
       -----------             ----------------------

       BRK Vector ------------ 7A55H

       User 0 ---------------- 7A46H

       User 1 ---------------- 7A49H

       User 2 ---------------- 7A4CH

       User 3 ---------------- 7A4FH

       User 4 ---------------- 7A52H




ZX65: Simulating a Micro                                        Page T4


                               *** TABLE 4 ***


       A command summary for ZX65 (in alphabetical order)
       --------------------------------------------------


       COMMAND         FUNCTION
       -------         --------

       C ------------- CPU register display & modify

       D ------------- Directory display of ZX65 files on drive B
                       Format: FILNAM.TYP    LOAD ADDR    # RECORDS

       E ------------- Examine block of memory. System will prompt
                       for starting address and number of bytes.

       G ------------- Go execute 6502 program per Current Program Counter.

       I ------------- Initialize a fresh disk on drive B. (Must be for-
                       matted.) System will prompt for verification.

       K ------------- Kill a ZX65 file on drive B. Similar to CP/M
                       ERA. System will prompt for file name.

       L ------------- Load a ZX65 file from drive B. System will prompt
                       for file name.

       M ------------- Memory substitution/modification. Use to view seq-
                       uential memory locations and update if desired.
                       System will prompt for address. Mode will then
                       continue in effect until a '.' is typed.

       R ------------- Load and run a ZX65 file from drive B, starting
                       at the address specified in the directory. (Must
                       be an executable 6502 program.)  System will
                       prompt for file name.

       S ------------- Save a ZX65 file on drive B. System will prompt
                       for file name, starting address, and number of
                       bytes.

       T ------------- Trace several 6502 instructions with display
                       following each step.  System will prompt for
                       desired number of steps.

       'SPACE' ------- Single-step command. System will execute one 6502
                       instruction, display the results, and stop.