A 6502 Software and Hardware Execution Simulator System =======================================================
with Code Debugging ===================
Using a Symbolic Assembler/Disassembler
DR 6502 AER 201S Engineering Design 6502 Execution Simulator ====================================================================
Simulator Manual By: M.J.Malone
1) Introduction 1
2) Simulator Modes of Operations 4
3) Stopped Mode Simulator Command Options 6
4) After The CRASH: Simulator Command Options 8
5) DRSYM and Debugging with the Symbolic Assembler/Disassembler 10
6) Explanation of Commands 12
7) Extended Instruction Set for the 65C02 and Rockwell R65C02 22
8) Differences Between DR6502 and the R6502, 65C02 and R65C02 23
9) DR 6502 Support Files 25
10) References 26
Appendix A: OpCode Alignment 27
Appendix B: Merging with EDIT/Blackbeard 30
Appendix C: Hardware Simulator Diagrams 31
DR6502 - A 6502 Software and Hardware Execution Simulator System
with Code Debugging Using a Symbolic Assembler/Disassembler
What is the Simulator and how does it work?
The 6502 is a digital circuit. Its reactions to logic levels
in interior registers and external memory locations are fixed. If the logic levels are all known in advance then the operations of the 6502 are determined. The simulator, using the same information as in a project target computer, traces the execution the 6502 would take. The simulator is a piece of software that runs on an IBM compatible computer. The simulator is programmed with the instruction set of the 6502. The task of tracing the movements a 6502 would make through a piece of code is tackled in the same way as any other computational problem. The fact that the IBM does not use the 6502 as its central processor is not relevant.
The hardware simulator is an interface card and cable that
plugs into the 6502 socket on an aerospace project board. The simulator software, if informed about the presence of the hardware card, uses it to perform reads and writes on the target computer's memory. This causes data to actually be read from and written to I/O ports allowing software debugging while the project hardware is present.
The simulator is a compiled BASIC program. It uses BASIC
variables to keep track of the processor registers and flags. The program 'grabs' a 160K chunk of a 512K IBM computer's high memory. Note that the operating system of the IBM is not consulted about the allocation of this memory and problems can occur. If you have only 256K the area of memory used simply does not exist. If you have a large number of memory resident programs that push the simulator code up into this area then the code will corrupt itself and will once again not work. 64K of that memory is used to record all of the data in the 64K address space of the 6502 if the hardware simulator card is not present. Another 64K is used to hold a status number for each memory location that indicates whether the memory is allocated, whether it is EPROM or RAM if it is RAM, whether a value has been written to it or not. This status number will also indicate if the corresponding memory location is to be found in the IBM's simulated 6502 address space or found via the hardware card on the target computer. This makes partial hardware simulation easy where some of the memory elements are accessed by the hardware board and others are assumed to be in the simulated address space. One example of this is EPROM emulation where the simulator accesses the real RAM and VIA on the target but looks to the IBM memory for the
program. The last 32K is used for internal variables and data. As a result, to run the simulator a system must have at least 373K of the lower 640K free:
DR 6502 Code 85K
Extra Data 160K 512-640K Unused 128K ------------------------- Total Required: 373K
Included among the files on the DR6502 disk is a program 'MM.COM'
which will tell the user how a system's memory is allocated. To run DR6502 it must respond with more than 373K free. If not, the AUTOEXEC.BAT and CONFIG.SYS files must be altered to remove some of the memory resident utilities or a RAM drive. Also included are two handy memory management utilities, 'MARK.COM' and 'RELEASE.COM' to mark a spot in memory and then later to release any memory resident utilities added after the mark.
The Procedure: What do you have to do to make it run?
As explained in the 'QIKSTART.DOC' file, the command line to
use in assembling 'myfile.asm' with TASM is as follows.
tasm -65 -b -l -fff myfile.asm myfile.bin myfile.lst <enter>
Note on Options: -65 : Assemble for the 6502
-b : Binary file output -l : List the symbol table -fff: Fill unassigned spaces of the EPROM with $FF
After the program is assembled, to produce a symbol file for
DR6502, the user must run DRSYM.EXE as follows:
The user must next provide the name of the listing file, in this
case 'myfile'. DRSYM produces a file 'myfile.sym' that can be read by DR6502. The user would next execute the DR6502 CONFIG program (if a different memory configuration is to be used):
The user then provides a description of the memory elements in the
system. When the EPROM is input, the CONFIG program will as for the name of the binary file, in this case 'myfile'. After the configuration is complete, the CONFIG program will automatically execute the DR6502 program. To run DR6502 with the same configuration as before and with a binary file of the same name and with a current or no symbol file then type:
The simulation begins.
The Simulation: What does DR6502 do when it runs?
The simulator constructs an exact memory map of your target
system with RAM, EPROM and VIA. The simulator then reads your .BIN program file produced by TASM into the spaces allocated as EPROM. (Note that the .BIN file is the form of your software that is ready to be burned on an EPROM and installed on your target system so the simulation will be exact.) The program then simulates the start up and running of the processor. Several run time error conditions are checked such as reads or writes to unallocated memory (not occupied by a chip), attempted writes to ROM space, reads from RAM spaces that were never set etc. Regular CPU crashes are recognized by the occurrence of undefined opcodes.
When using the hardware simulator option, the RST, NMI, IRQ, SO
and RDY signals are monitored in the hardware and are obeyed by the simulator. When used entirely in software, a simulated IRQ frequency is available (Search /Option 'i'/).
The simulator is called a symbolic code simulator because it
will read a ??.SYM file for each EPROM present in your simulated computer and will create a reverse symbol table. This table is then used in the 'P' program option and 'D' assembly code to allow the user to operate with the symbols that were used in the source code. This makes viewing and editing the code (Option 'P') much easier. With symbol information present, program outputs produced under Option 'D' could be combined back into the original assembly code to incorporate changes made during simulation sessions.
Other Benefits of the Hardware Simulator System
Once again, the hardware simulator is made up of two
components, an interface card and cable that plugs into an IBM mother board slot and the DR6502 program. The copy of DR6502 given out to all students is capable of operating in either hardware or software mode. If a student wishes to construct a hardware simulator card to use on their MS-DOS machine at home, the schematics are given in the notes. In addition to simulating the operation of the 6502 on the target board with DR6502, the interface card can be used to run diagnostics. The programs 'RAMTEST' and 'EPRMTEST' are used to test the RAM and EPROM chips respectively. The program 'EEPROM' can be used with the interface card to program electrically erasable, programmable read only memories or EEPROMs of the XL2864A type or equivalent. By installing the chip on your target computer board, plugging in the interface cable to your 6502 processor socket and running one of the above mentioned programs, all of these services are available through the interface card. Because students sometimes wish to test chips outside their board or would like to test their VIA chips, an auxiliary board is provided with ZIF (zero insertion force) sockets that uses a project computer board as its base. The board has been specially wired to allow testing of RAM, EPROM, and VIA or programming of EEPROMs.
2) Simulator Modes of Operations
The program can run in one of four modes given by the
combinations of user output/no output and break point set/no break point set. Each of the four modes gives a different amount of user feedback and executes instructions at a different speed.
When the simulator reports to the screen after every program step, the execution is quite slow in comparison to the speed of a 6502. To speed up the execution of the program, the user has the option to suppress screen printing thereby saving a great deal of time. Note that any time screen output is selected, the history file (DR_6502.HST) is updated as per its user selected output option. When the screen output is suppressed, the history file is not written to either. (Search /Option 'H'/)
Trace Controlled Screen Output:
The simulator has a control option (Search /Option 't'/) where the screen output is enabled and disabled based on the position of execution in the subroutine calling tree. This option is called the trace option because it can be used to trace the execution of a particular routine, performing all of the calculations in subroutines without displaying them. The speed of execution of the simulator is not effected whether operating under the trace mode or not however as the trace option changes execution modes, the speed changes accordingly.
Break Point Set:
If the 'processor' encounters the one user selected break point address during any memory access (OpCode fetch, read, write etc) the simulation will stop and await user prompting. If there is no break point set then no check of addresses will be done. (Search /Option 'b'/)
Mode 1: Break Point and No Output
The fastest execution occurs when a break point has been set
and no output is selected. In this mode the 'processor' blasts along at maximum speed scanning for the ` key which indicates switching back to full user output. Without user input the program will run 'silently' until the breakpoint address is reached. At maximum, the program is currently capable of simulating about 166 MCPS (machine cycles per second) or one second of 6502 CPU time in about 1.67hr of XT (8Mhz) execution time which is 1/6000th real speed. With delay loops disabled, this mode can move very rapidly though the program, executing about one page of assembly source code per second. Since most every computer owned by students is many times faster than an XT, the simulation will be that much faster on their machine at home. If the break point address is reached, the program will switch to Mode 4: Stopped Mode.
Mode 2: No Output, No Break Point
The program still scans for the ` key because with no break
point this is the only means of returning the program to full output mode. Since the program will run indefinitely in this mode, the user needs to know at what stage the program is so that it may be stopped near points of interest. The program prints the current program counter value to the screen after each program step to let the user know where the program is. This mode runs at about 118 MCPS, that is 70% of the speed of mode 1.
Mode 3: Full Output
In this mode the program prints the values of all registers
after every program step. If there is a break point set then the current fetch and program addresses will be compared to the break point address at each program step. If the program reaches the break point address it will go into Mode 4: Stopped Mode. Running with full output with or without a breakpoint is very slow but still faster than the average human is able to absorb the information flipping past on the screen. For this reason the program builds a DR_6502.HST history file on disk that records any program steps that are displayed on the screen. In this mode the simulator executes about 16 MCPS or about 1/10th the speed of mode 1 including all disk and screen output. In this mode the program is scanning for user input. To transfer to modes 1 or 2 press the ` key. To stop the execution (go to Mode 4: Stopped Mode) press the 's' key (stands for 'STOP').
Mode 4: Stopped Mode
In this mode the program does not execute program steps but
waits for user input. To go back to each of the other modes from mode 4, the user must input:
Mode 1: Enter a [new] break point address. Press the ` key.
Mode 2: Press the ` key. Mode 3: Press the 'g' key (stands for GO)
To remain in stopped mode but advance by one program step, the
user can press the 's' key (stands for STEP). The other command options available are explained in the next section.
3) Stopped Mode Simulator Command Options
Since there are several avenues open to the user under the
stopped mode, no command prompt is displayed but the program will react to keystrokes. The following is a list of the keystrokes and the commands they initiate. The more complete description of what each of the commands does is given in below. The reader can use a word search or find option searching for /Option 'x'/ where x is the keystroke to be searched.
Key | Function
==================================================================== | b | Set the break point address | t | Trace on, Full screen output for this level subroutine | only. Screen output is disabled upon JSR and is | re-enabled after the matching RTS is executed. | T | Trace off | d | Dump memory data to a disk file in hex, TASM or block | format | R | Read a disk data file in block format into memory | * D | Dump Disassembled Program to a Disk file in TASM format | p | Poke values into memory (good for simulating I/O, sensors) | * P | (Re)Program: Disassembles a Page of Program Memory and | Offers the following sub-menu | | Key Function | ========================================================== | u move Up a line in the program | d move Down a line in the program | c Change the code - begin reprogramming in assembly | code | s Save current page | r Reread current page discarding any changes | + read and disassemble the next memory page of the | program | p read and disassemble a different Page | m Make space for new assembly code to be inserted | i Symbol information | a Assign a Symbol | l Label current line with a symbol | b toggle display of Branch line labels | n modify Notepad | q Quit Program module - do not save the current page | |
m | Monitor an address (variable)
| r | Change the contents of the processor Registers including | the flags | v | View memory in hex dump format to the screen | n | Display and edit the notepad | l | List a text file to the screen - copy to notepad | f - find text | ESC - quit | h | History, display the short history that is maintained in | memory | H | Change the history file and short history format | ! | RESET the processor - all memory remains | i | Set interrupt frequency (Available only in software | simulation mode) | e | End the simulation - Check DR_6502.HST for a log of that | run | ? | HELP - List the Keystrokes available to the user | ==================================================================== * Segments contained in the second overlay. Upon initiating the command the simulator will stop for a few moments to transfer in 'OVERLAY1.EXE'. These segments of the program utilize the symbol information if present to enhance their operation. Please see section 5) DRSYM and the Symbolic Debugging.
4) After The CRASH: Simulator Command Options
After the simulator has flagged some condition that would lead
to a malfunction of a real 6502 system, the mode of operations changes to the post crash analysis. The user has many option available to analyze memory and processor status to discover where things went wrong. The user also has the option to direct the simulator to return to normal operations after some adjustments to registers or data has been made. The following is a list of commands available in the post crash analysis.
Key | Function
==================================================================== | d | Dump memory data to a disk file in hex, TASM or block | format | * D | Dump Disassembled Program to a Disk file in TASM format | p | Poke values into memory (good for simulating I/O, sensors) | * P | (Re)Program: Disassembles a Page of Program Memory and | Offers the following sub-menu | | Key Function | ========================================================== | u move Up a line in the program | d move Down a line in the program | c Change the code - begin reprogramming in assembly | code | s Save current page | r Reread current page discarding any changes | + read and disassemble the next memory page of the | program | p read and disassemble a different Page | m Make space for new assembly code to be inserted | i Symbol information | a Assign a Symbol | l Label current line with a symbol | b toggle display of Branch line labels | n modify Notepad | q Quit Program module - do not save the current page | | r | Change the contents of the processor Registers including | the flags | v | View memory in hex dump format to the screen | n | Display and edit the notepad | h | History, display the short history that is maintained in | memory |
H | Change the history file and short history format
| ! | RESET the processor - all memory remains | e | End the simulation - Check DR_6502.HST for a log of that | run | ? | HELP - List the Keystrokes available to the user | j | Jump Start the simulation - Direct the simulator to resume | ==================================================================== * Segments contained in the second overlay. Upon initiating the command the simulator will stop for a few moments to transfer in 'OVERLAY1.EXE'. These segments of the program utilize the symbol information if present to enhance their operation. Please see section 5) DRSYM and the Symbolic Debugging.
5) DRSYM and Debugging with the Symbolic Assembler/Disassembler
DRSYM is a very short program that reads the symbol table
printed in ASC II at the end of the TASM list file and turns it into a packed binary file for input into DR6502. DRSYM also excludes from the list of symbols it produces, any symbols that appear anywhere in the assembly code as constant arguments in the format '#symbol'. The reasons for this will be explained later. If another assembler is used other than TASM, a different DRSYM program will need to be programmed. For this reason both the BASIC source code and compiled code for DRSYM have been provided so that the user may alter the program to read the list file from their favorite assembler. With the symbol information and the machine code the simulator is able to recreate your assembly code fairly closely. The two program modules that use this ability are the 'D' dump assembly code to disk file and the 'P' (re)program assembly code modules.
'D' Dump Assembly Code Option -----------------------------
The 'D' dump code option is quite straight forward. The
simulator looks at the section of memory to be disassembled and dumped to the disk and inserts labels whenever it finds a match between an address reference and a label value.
Labels are not substituted in the case of constant references since there may be times when #$01 is used as the 'number 1', 'bit zero set' or 'true' each with a different label. It would be impossible for the simulator to determine which usage of the #$01 was intended in a particular piece of code. Since constants are never substituted for, there is no need for constant labels to appear in the symbol table. For this reason, DRSYM does not record constants labels in the symbol table in the .SYM file.
Address with No Symbol
References to addresses that do not have a corresponding label but are only a few bytes offset from a label will be recorded as 'label+offset' assuming a multibyte storage data structure. For example, if 'Register_0' where assigned the value of $00 in the source assembly code and no label were assigned to the address $01, it is very likely that references to the address $01 would actually be written in the code as 'Register_0 + 1' where Register_0 is in this case a multibyte piece of data. If contents of address $01 had absolutely nothing to do with the contents of address $00 then, as dictated by good programming style, $01 should have been assigned a label that explained its purpose such as 'Register_1' or 'Temp'.
Though these rules may not seem to make sense when stated,
experimentation has found, on average, this set of rules produces code that is closest to the original assembly source code. It is very possible that the code reproduced by DR6502 will be identical
to the original source code with the omission of the comments. The
dump module is not interactive, the output of the symbolic disassembly goes directly to the user specified disk filename. The output of the dump option is easily incorporated into the original source code to reflect reprogramming done in the 'P' (re)program code option.
'P' (re)Program Code Option ---------------------------
The 'P' (re)program code option is an interactive symbolic assembler/disassembler based on a machine language page of assembly code. As with the 'D' dump option the 'P' option disassembles starting at a user specified memory address inserting address labels in the same manner as described above. The disassembled code is displayed on the screen and the user can move up and down through the page. The user can inquire about label information, assign a new label or label the current memory address indicated by the line the cursor is currently on. The user can modify the code and use labels to specify any arguments including constant arguments (like #True for #$01).
Sample Stopped Mode Entry
Each time the user presses the 's' key whether to stop
execution or to step execution by one step the value of all registers is written to the history file.
Time=000000.000042 million cycles
Registers: Acc=$01 Xreg=$FF Yreg=$00 SP=$00 PC=$F01E N V 1 B D I Z C 0 0 1 0 0 0 0 0 ------------------------------------------------------------------------
Sample NOP Special Execution Entry
Often a program will contain large areas that contain nothing but NOP no operation instructions. Since these instructions do not modify memory, registers or program flow, they are given a special notation in the history file to save space.
NOP Cruise $F005-$F009
F009 EA NOP (10) 00 FF 00 FF F009=>F00A 10100000 0080=#$???? -----------------------------------------------------------------------
In software simulation mode, there is no target computer to
provide NMI or IRQ signals. The simulator provides an option where one interrupt signal can be simulated at a user defined frequency (period given in clock cycles). This 'signal' can be blocked by the interrupt flag in the processor status register. This 'signal' can be blocked by the interrupt flag in the processor status register and uses the IRQ jump vector so it is a close simulation of the IRQ function of the processor.
The 'e' end option allows the user to end the simulation
session. The history file maintained on the disk is closed and the simulator returns the use stopped or crashed mode.
The 'n' Notepad Option
A minor deficiency in the DR6502 program was the necessity for
the user to constantly be making note of addresses so that they may be correctly input to another option of the program etc. Such minor note taking has been taken care of by the 'n' option where the user is given four lines at the top of the screen (used for errors and warnings only) to make notes of any kind. This area of the screen is not erased after the user exits the notepad option and may stay for quite a while. The contents of the note pad can always be called up again if they are erased.
The 'l' List Text File Option
Sometimes the user would like to check a text file for
information necessary to the debugging of the code under testing. Commonly the user would like check the source or listing files from the assembly code but this option allows any text file to be examined including this documentation file for DR6502. The reading of the text file is one way, forward only, with one line read for each keystroke. The 'f' key in this mode invokes a find or search function. The <ESC> ends this option. On exiting this option the user is allowed the option to copy the portion of the file displayed into the notepad so that it may be edited and redisplayed. Note: there is no facility to copy the contents of the notepad back to the file or to a different file so this cannot be used for file editing.
The 'v' view memory option allows the user to display portions
of the 6502 virtual memory to the screen. With this option the user can check the data values at any point in the execution of the program code. The memory is listed beginning at a user supplied address and then the user has the option of paging up and down through the memory using the 'u' and 'd' keys.
The 'd' dump data option is conceptually equivalent to the 'v'
view option. The dump option allows the user to dump the contents the 6502 virtual memory to a disk file in hex format for later inspection or merging into a TASM source file. This allows the user to take data generated by 6502 commands and incorporate it into the source code. The 'd' option dumps a section of memory to a disk
file in one of two formats, either in hex format:
F000 A9 00 8D 00 02 CD ……..
for easy (?) interpretation later or in 'TASM' format:
for easy merging with the program source code to make it a data
table. (see Appendix A)
The user may also record the data in a 'block' format in the
data file. The block format is useful for recording memory values to be read back into memory later using the 'R' option. The format of a 'block' file is as follows:
0, 1, 2, 3, 4, 5, 6, 7 8, 9, 10, 11, 12, 13, 14, 15 -1, 0, 0, 0, 0, 0, 0, 0
The first number '4096' corresponds to the address in memory,
in this case $1000 at the beginning of the data block. The numbers that follow, in rows of 8, are the values of the memory locations sequentially following the beginning address of the data block. The last line must begin with a -1 followed by 7 other numbers. All numbers (except the -1) must be in the range 0-255.
The 'R' read data option inputs data from disk files into the
6502 ram memory in a block format (see Option 'd', 'block' output as described above). The data file may be produced by DR6502 by the 'd' option or may be created by a user with a text editor. See the 'd' option above for details on the format.
The 'p' poke option allows the user to directly write to RAM
spaces within the 6502 virtual memory map. The user supplies a start address and fills in the values in that and successive locations by separating the figures with spaces. The user can prefix the data with '$' or '%' to indicate hexidecimal format or binary format respectively. If no prefix is included, the data is assumed to be decimal. Once a prefix is attached to the first figure, all other figures input on that line are assumed to be in the same format and no further prefixes are required. For example, typing:
$7f 6a f2 00 37
would place $7F in the specified memory location and $F2, $00 and
$37 int and no further prefixes are required. For example, typing:
$7f 6a f2 00 37
would place $7F in the specified memory location and $F2, $00 and
$37 in the next 3 memory locations.
The 'D' dump program option is used to dump a disassembled copy
of the program in a user specified memory range to disk. If symbol information is read into DR6502 then the disassembled listing will contain symbolic representations for any address references in arguments. This allows the user to make changes in the code permanent. (See Appendix B: Merging with EDIT/Blackbeard to recognize the possibilities here)
The 'P' (re)program option reads, disassembles and displays 256
bytes or one page of program code starting at a user selected address. The user may then move a cursor '=>' up and down ('u' and 'd') line by line through the disassembled page. The user may quit the 'P' (re)program option with the 'q' key. The '+' key causes the simulator to read the Next page of assembly code. If the user would like to look at a different part of the code, the 'p' causes the simulator to read a new page of code starting at a user specified address. Using these commands and the 'u' and 'd' commands this is similar to a 'view code' mode however there are other subcommand options that allow the user to alter the program at the assembly language level.
The 'c' change suboption allows the user to input lines of
assembly code as opcodes and operands. Note that labels and macros are not allowed since this is a line by line assembly process. Be warned that the change suboption overwrites the bytes of code that were in the locations prior to changing. If the change requires more than a simple substitution or if the user is not certain that the opcode alignment will be preserved after the change then the make space option (described below) should be used first.
All editing of the code is done in a buffer so that if
mistakes are made in changes to the code, the actual 6502 memory map can be read again to retrieve the original program. The 's' save subcommand saves the current page of assembly code back into the 6502 virtual memory. This does not make the change permanent (to the binary file) but will remain for the rest of the session with the simulator. If the user would like to make program changes made in the simulator permanent then consult the 'D' option of the Stopped Mode commands.
If the user has made changes to the program in the buffer and
would like to discard them and reread the program from the 6502
virtual memory then the 'r' reread option is available. This will
discard any changes that may have been made in 'c' change operations but will not discard changes that have been saved with the 's' save option. If a virgin copy of the program is required then the user must exit the simulator and start over so that the .BIN file can be reread.
The simulator is capable of reading a file of symbol
information if one is produced using DRSYM. Whether a file has been input or not the user can 'a' assign values to new symbols or 'l' label the current memory address with a symbol (as with branch labels). The user can search the list of symbols for 'i' information, either the symbol assigned to an address or the address represented by an symbol. Users may prefer to see or not to see the branch line labels in the assembly code and these can be toggled on and off by the 'b' option.
The user is able to make notes in the notepad with the 'n'
suboption of the 'P' option. This is the same notepad as is accessed from the stopped status screen and is very useful for making note of address, labels or diagnostic states.
When the user has found that an error has been made and some
code has been omitted, the 'c' change suboption is not sufficient. The user must first open up a space in the program for the omitted code to be inserted. The 'm' make space option does just this. Here is a graphical representation of the 'make space' process
Program Start Addr >
| | | | | | | | | A | | A | | | | | Cut ____|___________| |___________| Here | | | | | | | NOP Filler| | B | Slide down ____|___________| | | to here | | | | | | Program End Addr > ============= | B | | | | | | | | | =============
…………. End of Eprom ………….
Process in Brief:
1) Program sections (A+B) are searched for address references to the
B section (JMPs, JSRs, Branches, Data access like LDA, STA etc). The references are adjusted to reflect the relocation of the B section of the program. Two possible error conditions can arise during this adjustment. Relative branches have a maximum length of 128
bytes. If a relative branch forward or backward crosses the cut
line and the added length of the branch due to the inserted section exceeds the maximum length of a branch then an error is counted and the branch is recorded as Bxx $FE. This will result in an endless loop if the branch is taken but will also be easier to find if you have to change it. Absolute addresses must fall into the range of $0000-$FFFF. If the user has miscalculated and tries to make so much space that the end of the B section of the code is pushed off the end of the EPROM space (past $FFFF) then another error will occur. If an absolute address plus the offset of the move exceeds $FFFF then these are counted as errors and the address is recorded as $0000. This would happen for references to the part of B that is pushed off the end of the EPROM. If any symbol information has been input into DR6502, either with a .SYM file at the beginning of the session of during the session with the 'a' assign symbol or 'l' label current address commands, then these symbols are adjusted as well. The code will automatically adjust all address labels that fall into the range of code being moved. Since labels used to represent constants (as opposed to those used to represent addresses) are not present in the symbol table as created by DRSYM, the DR6502 system attempts to shield the user from the following problem. In the rare instance that the user has used the 'a' assign symbol to assign a symbol used as a constant AND has assembly code on the zero page AND uses the 'm' make space option to move it, the following can be a problem. There is the possibility that constant symbols may be confused for address labels. If for instance the code being moved was in the range $0060-$0090 and a constant label like 'Bit_7_set = $80' is assigned by the user during the simulator session, then DR6502 will mistakenly adjust this label's value interpreting it as an address. This has NO EFFECT on the actual code since in the memory of the 6502, TASM has already removed the symbols from the machine code. This also has NO EFFECT on the disassembled outputs produced by DR6502 in the 'D' or 'P' options since constant arguments are never substituted for. In the 'D' option however, at the beginning of the file produced, DR6502 writes out the values of all the symbols in the form of assembly language assignment statements. (This allows the 'D' dumped code to be reassembled directly if the user desires.) In the list of assignments the label 'Bit_7_set = ...' will have an adjusted address.
2) The slide is performed, regardless of any errors that were
encountered. The simulator was programmed assuming the user knows what they are doing, allowing users who know what they are doing to do some very unusual things. If one of the errors mentioned above occurs and you were not anticipating it then it may be best to end the session and start again with a virgin copy of the binary code.
3) The space opened up is then filled with NOP instructions. Since
NOP instructions are one byte long, they can be replaced in the 'c' change option in reprogramming the code without worrying about the opcode alignment. The simulator is optimized to execute a memory space filled with NOP instructions very quickly so the user need not worry about opening up a little more space than is required by the code to be inserted.
The 'm' make space subcommand requires the user to input the
first and last program space addresses to define the space A+B. The address of the first opcode of section B is input to define the position of the cut. The new address of the first opcode of section B is input to define the offset of the relocation. Spaces can only be created by this method. If a data table is present then care must be taken that it has been handled in one of the ways as described below.
Address references are CORRECTED for the new location of the
relocated part of the code but ONLY within a user specified 'program' area. Herein lies another problem. A program is a thin line of opcode alignment; shift by one byte and a program starts looking like a random stream of bytes. (See Appendix A for an explanation/definition of opcode alignment) Given a valid program opcode address as a starting point, a program can be traced and address references to the area of relocated code can be adjusted. If the program encounters a 'data' space half way through the 'program' space it is not trivial for the program to determine where the data space ends and the program space resumes since op-code misalignment can make programs look like data and coincidental data may appear to be a program. As a result, if this relocate option of DR6502 is to be used one of three arrangements must be used. NOTE: the described options are only necessary if DATA (.BYTE or .WORD) directives have been included in the eprom.
One option is to put user data tables that are to be burned
into the eprom at the beginning of the eprom before the program code. In this case, the user specified 'program' space defined for the purposes of address reference adjustments would be specified from after the data table to the end of the program. (Note NOT the end of the eprom! If the user hopes to create a blank space in the program space then the end of the program cannot be specified as the last address of the eprom or the memory shift will result in 'spillage' off the high end of the eprom.)
A second option is to put the data directly after the program.
In this case two things are necessary. First the data must be defined as part of the program space so that it is relocated along with the code instead of being overwritten. This will also make sure that address references to the data table will be corrected. At least one non-opcode byte must appear between the program and the data table so that when DR6502 encounters this byte it will know a data table has started and it will not attempt to interpret any bytes that follow as opcodes or operands. Any non-opcode byte would do just fine.
A third option is to put the data table at the very highest
address of the eprom, leaving a space between the end of the program and the beginning of the data. In this case when defining the 'program' section, do not include the data. The relocated program will move closer to the data when slid toward higher memory to make room for more program lines.
7) Extended Instruction Set for the 65C02 and Rockwell R65C02
With the development of the AER 201S computer board, which uses
the 65C02, it became more necessary for DR6502 to handle the extended CMOS instruction set. Since the R65C02 is commonly available, the specialty Rockwell instructions may also be required. The following instructions were therefore added:
Branch Bit Reset (R65C02):
BBR0 zpage,rel ; BBR1, BBR2, BBR3, BBR4, BBR5, BBR6, BBR7
Branch Bit Set (R65C02):
BBS0 zpage,rel ; BBS1, BBS2, BBS3, BBS4, BBS5, BBS6, BBS7
BRanch Always (65C02):
PusH/PulL X and Y (65C02):
PHX, PHY, PLX, PLY
Reset memory bit (R65C02):
RMB0 zpage ; RMB1, RMB2, RMB3, RMB4, RMB5, RMB6, RMB7
Set Memory Bit (R65C02):
SMB0 zpage ; SMB1, SMB2, SMB3, SMB4, SMB5, SMB6, SMB7
STore #$00 Zero into a memory location (65C02):
STZ address mode
Test and Reset Bits (65C02):
TRB address mode
Test and Set Bits (65C02):
TSB address mode
Note that no accurate number of clock cycles durations were
available for the R65C02 instructions so estimates were used based on other 6502 instructions.
The simple indirect (zpage) address mode was also added for memory
fetches as per the 65C02 standard. The special address/argument structure of the BBSx and BBRx of zpage,rel is also supported.
8) Differences Between DR6502 and the R6502, 65C02 and R65C02
Reference 3, Hendrix, details some anomalies in the operation
of the 6502 in Chapter 6 'Quirks, Bugs and Other Oddities of the 6502' which will be mentioned shortly. The simulator was not programmed intentionally to imitate any of these problems in the 6502. When using the add or subtract instructions in decimal mode on the NMOS 6502, the Negative flag, Overflow flag and Zero flags are not valid. On the 65C02 they are valid however the instructions require one more clock cycle. In the simulator they are valid, regardless of 6502 version simulated and the execution clock cycles used are correct for the type of processor selected. If the simulator is used to simulate an NMOS 6502 using the add and subtract in decimal mode and makes use of the N, V or Z flags, the simulation will not match the real (errant) execution of the NMOS 6502. When using the indirect jump with a the address of a page (ie: ending with $FF), an NMOS 6502 does not fetch the high byte of the jump vector from the first byte of the next page but incorrectly from the first byte of the current page. In NMOS 6502 mode, the simulator flags JMP ($xxFF) as an error because on a 6502 it leads to an incorrect jump. It is assumed that no program is designed to exploit this error. The 65C02 does the jump correctly requiring an addition clock cycle as does the simulator in 65C02 and R65C02 mode. The unimplemented opcodes on the NMOS 6502 do unpredictable things, sometimes crashing the CPU. The unimplemented opcodes on the 65C02 and R65C02 are taken as NOP instructions. All unimplemented NMOS 6502, 65C02 and R65C02 instructions are interpreted as crash codes by the simulator since it is assumed a user will never use an invalid code in the intended program. The 6502 has no such thing as an idle bus cycle. In all cycles there must be either a read from or a write to memory. The NMOS 6502, 65C02 and R65C02 all perform an extraneous read when executing a absolute indexed addressing mode. The NMOS 6502 reads the next byte after the instruction's argument, sometimes causing an error with I/O devices that are sensitive to having their port memory location read. The 65C02 and R65C02 both read the last byte of the present instruction with less chance of such an error. The simulator does not perform any extraneous reads. The NMOS 6502 does not modify the decimal mode flag in the processor status register in a reset operation or an interrupt. The 65C02 and R65C02 does clear the decimal mode flag in these two cases. The simulator clears the decimal flag for all resets regardless of the processor chosen. The simulator clears the decimal flag on interrupts only in the case of 65C02 and R65C02 processors. The NMOS 6502 requires 7 machine cycles to perform an absolute indexed read/modify/write operator type instruction such as INC, ASL or ROR. The 65C02 and R65C02 requires only 6 cycles to do the same instructions in that particular addressing mode. The simulator uses the correct number of cycles in each case. The NMOS 6502 does not save any information on receiving a reset signal. The 65C02 and R65C02 saves information on reset consistent with an interrupt signal. The simulator does not save
any information on reset regardless of which processor it is
emulating. In read/modify/write operator instructions such as DEC, LSR or ROL there is an 'idle' bus cycle during the modify operation. As mentioned above there is no such thing as an idle cycle for the 6502, either a read or a write must be performed. In the case of these type of instructions, either a read or a write is performed in the modify cycle to the address that will be written to on the following cycle. Once again, unnecessary reads or writes can cause problems with peripheral ports. The simulator does not do the extraneous read or write.
All of the above cases where the simulator deviates from the
processors, the instances are rare or the true behaviour is undesirable. Any other deviations from the simulation of the actual behaviour of the processor chosen is an error in the simulator. Though not many such errors are likely to exist in the program, there are undoubtedly a few left. Such errors will be fixed as soon as they are identified by a user or a user supplies a minimum length program (5-10 lines) and the simulator commands that will cause the error every time.
9) DR 6502 Support Files
List of Files Necessary to the Operation of the Simulator
DR6502.EXE - Main executable code of the simulator
OVERLAY1.EXE - Second module of the simulator program CONFIG.EXE - Creates Memory Map 'CONFIG' files for your target BLANK.BAS - A file used to initialize the 6502 virtual memory CINST.SET - 6502, 65C02 and R65C02 Instruction sets DRSYM.EXE - Symbol table preparation program DRSYM.BAS - The BASIC source code for DRSYM.EXE MM.COM - Utility to display memory allocation MARK.COM - A memory resident utility whose purpose is to mark a point in memory RELEASE.COM - A memory utility used to release all memory resident programs added after the last mark in memory
1) Commodore 64 Reference Manual, Chapter 5: Machine Language,
2) The Transactor, Volume 4, Issue 05, pp52-53 (Reprinted in your
3) Steven P. Hendrix, The 6502, 65C02 and 65816 Handbook, Weber
Systems Inc., Cleveland, Ohio, 1986, pp221-227
Appendix A: OpCode Alignment
Note that the 65C02 will not necessarily have the same problems
as a 6502 with opcode alignment, it will have worse problems actually. Please read on and the differences will be explained. So you aren't quite clear on what exactly I mean by opcode alignment. Consider this question: How many groves are there in the average phonograph record? The answer is one (or maybe two - one on each side). This is a very unique condition if you think about it: Put the needle down anywhere and the record will always play the same series of songs. A few years back there was at least one novelty record made where there were two groves, two possible series of songs depending on the original placement of the needle on the record. This record is conceptually similar to an assembly program, where the songs represent the instructions in the program. The series of songs played depends on the starting point on the record, whether grove one or two is chosen. There are only two possible 'programs' available to the listener. Only the radial starting point in the record determines what portion of two 'programs' are played. An assembly language program however is more closely comparable to a Snakes and Ladders game with rich interconnections than to the sequential nature of a recording. I know, you are saying hold on now, I have only one program, I used the assembler, where is this other program you are talking about? Well you are absolutely right, you have only one program: in assembly. In machine code it is just numbers in an EPROM. Try looking at machine code even when you know what is supposed to be there: the program is not obvious. The key point is recognizing what bytes represent opcodes and what bytes represent operands. To the human eye opcodes, 'pop' out from inspection. A9 - LDA; 8D - STA; 20 - JSR Your brain sees these and recognizes the pattern. The 6502 is not blessed with this ability to 'see' what are opcodes and what are not. All it knows is the next byte it fetches will be an opcode, then the operands, then another opcode. Where you start determines what the 6502 interprets as the first instruction and the course of the program from then on. Using an assembler assures that opcodes will be in the right spot at the right time and things will go just fine, provided no .BYTE directives are placed in the middle of a piece of code. The problem arises when the user starts hacking around with a piece of software with a tool like DR6502. If the code has an error or if the user messes up the program, an operand may be fetched instead of an opcode and all of a sudden the 6502 is executing a very different program. So just how many of these alternate universe programs are there in a given piece of machine code? Well, if you have 4k of code, if we take 35-50% of those bytes to be opcodes and the rest operands then there are a good 2000 possible alternate universes that your 6502 could fall into. There is some good news and some bad news. These alternate programs are very unstable (and erratic) and they usually do one of two things after a few opcode fetches. They either crash (that's the good news, because you know you have a problem) after fetching an bad opcode or they fall back in line with the proper opcode alignment and things go back to normal. This is very bad since you may have a 'mysterious' error that you have no idea what is going on with. Now what are the probabilities for all
of this? Of all the 256 opcodes, about 151 correspond to valid
opcodes, about 35 crash the CPU outright and the other 70 or so are weird combinations of incrementing and adding with strange flag results. In a real 6502 system, the CPU has a (151+70)/256 chance of continuing to execute. Upon the completion of each opcode there is the chance that the proper opcode stream may be rejoined. The chance therefore of an outright crash is low. The bottom line: this is bad news. Someone, in a stroke of genius, said lets make the 65C02 better. Lets make all of the undefined opcodes behave as NOP's. The 65C02 can NEVER crash. After hopping into the wrong opcode alignment, the 65C02 will execute a maximum of two undefined opcodes in a row before rejoining the proper opcode alignment. The difficulty is that the 65C02 has a great number more defined opcodes so a 'strange' program will execute for a long time before hitting an undefined opcode, executing a NOP and rejoining the proper opcode stream (possibly). If you are operating DR6502 and have used only regular 6502 instructions then you should use DR6502 in 6502 mode. This will cause the simulator to object to a wider array of mistakes and more quickly. The overall landscape of a section of machine code if compared to a record would have a great many possible paths threading near the intended opcode path. The alternate paths would be short lived in general and would most frequently rejoin the main path but would occasionally dead end in a crash. The Snakes and Ladders interpretation necessary when considering loops in the real code and accidental branches, JMPs, RTS, JSR statements in the parallel codes would not look very different since a quick count gives only (8+1+2+2)=13 program counter modifying opcodes out of the 151 legal codes. If the proportion is the same for the illegal 70 or so codes then the chances of an accidental jump is only about 1 in 10. These instances are catastrophes since the destination (by Murphy's Law) is nearly always a pure data space where there is no opcode line to be rejoined and the results can be very erratic.
In summary: How do you get off track and how to avoid it? The
easiest way is to push data into the stack in a subroutine and forget to pull it off again before executing an RTS (frightfully common error). Mishandling interrupts, etc could be a real problem usually in the misbalance of the stack and return addresses. Doing little tricks like using the address pushed on the stack after a JSR in a calculation and returning the wrong number to the stack or using calculated JMPs using a push and RTS method and messing up the address etc would do it too. If you use DR6502 you could do it in one careless p-poke command or not watching what you are doing while using the P-program command. The best way to avoid the alignment problem is knowing it exists and being very careful of the stack and changes to the program.
An exercise: If you want to see what an alternate universe
program looks like, invoke the P-program function on DR6052 with a program loaded. If your code starts at $E000 try giving DR6502 the page start address of $E000+a random number that does not correspond to an opcode address and observe the results. 105/256 opcodes will show up as .BYTE directives which means you have no idea what a real 6502 would do. 70% of the time it will do something, with some
operands and lead to another opcode fetch. 30% of the time
(anything $x2 or $xF is usually a crash) it will lead to a crash. DR6502 traps all undefined opcodes as errors and halts execution.
The 65C02 was improved to define all undefined opcopes to be
NOPs so that alternate program streams will never crash the system. As pointed out before, the alternate program lines that rejoin the main program line are more mysterious and dangerous than ones that crash the computer outright. DR6502 still considers all non-allocated 65C02 opcodes as crashes and halts the 'processor'. This is done because in the actual program such codes should never occur and when they do it is a sure sign that something is wrong.
Appendix B: Merging with EDIT/Blackbeard
You have probably found yourself reading this because you have
a section of 'invented' assembly that you made up to patch a bug found while using DR6502 in one file and your original code in another file. The merging process is a simple one:
1) edit the original file
2) ctrl-F2 to switch to window #2 (see Windows-Switch-window#2 in ESC help menus) 3) ctrl-n to select a new file for window #2 (see Files-Newfile in help) and enter the filename of the 'invented' section of code. 4) 'Copy' the desired section of the code from the 'invented' file using f1 to mark the top of the range, f2 to mark the line after the end of the range, f3 to copy this range into the paste buffer. (transfer smaller blocks if the whole block is too large for the paste buffer - shift f9 clears the paste buffer) 5) ctrl-f1 to switch back to window#1 where the original source code is. 6) Cursor to the line that the range is to be inserted before and press f7. 7) Make what ever other changes are necessary and 8) ctrl-z to save!