MOTOROLA M6800 EMULATOR Version 1.0 1 - May - 1991 Kevin Bertram INTRODUCTION This implementation of the M6800 Emulator is version 1.0. If you find any errors with the Emulator or debugger or maybe there are a few suggestions as to what you might like to see in the program to enhance its usefulness then please let me know. My address is further down in this manual. Also this program and manual can be copied as many times as you want and given to friends if you please. There is no hassle with this. But do not sell it! The program is public domain and not for profit making. The purpose of this Emulator is to replicate the instruction set execution of a CPU not present within the hardware design of the IBM-pc-xt/at or a clone there-of. Or for that matter any host computer that is capable of executing programs. The instruction set of the emulated CPU must be adhered to exactly otherwise programs written for the emulated CPU will not perform correctly in the target system. This program in particular has been adapted to suit the Motorola M6800 8 bit CPU. An emulator can be a useful program. Especially if you are into constructing and programming your own micro- controllers. They provide for a safe environment at which new code can be tested under reasonably tight control before being downloaded to the target machine and let loose. Also the emulator allows for a foreign CPU's machine code to execute under a host CPU. Which is most likely where the cross-assembler will reside too. All this adds to faster implementation of your program and gets you to using your hardware sooner. I will not enter into the reasons as to why a designer might use 8 bit CPU's as opposed to 16 of 32 bit CPU's but rather that what ever his or her choice is they might find a need to check out the integrity of the program code before 'burning it in'. It could be that the program will have to be executed step by step to find an illusive fault. And in this case an emulator could prove useful. If the target machine already has a debugger built in then there might be no need for an emulator but if there is not then an emulator will be needed. My reason for producing an Emulator for the M6800 is mainly because it was the first CPU I had encountered and so I am biased towards it. Another is that, as far I am aware, there are no other programs that will emulate a M6800 CPU running under an Intel CPU and as I have a need for one right now I wrote this program as a response. So here it is. It was a joy to work on and I hope you find it useful. Kevin Bertram Electronic mail ACSNET - kevin@latcs1.oz Surface mail: Department of Computer Science La-trobe University Plenty road Bundoora, 3083 Melbourne, Victoria Australia. ACKNOWLEDGEMENTS I would like to thank Ira Baxter for his excellent suggestions in speeding up the Emulator to the effect of ten times as compared to its intial implementation. I would like to thank Mark Seiffert also who, along with Ira, sourced me with M6800 code to run through the Emulator to test its validity. [I find it is much better to have someone else test my software because they will not step around the precarious parts of the program.] DISTRIBUTION FILES There should be the following files contained within the archive file. 68EM.COM M6800 Emulator configured for a standard IBM-pc-xt/at 68EMV.COM M6800 Emulator configured for an IBM-pc with a VT-100 terminal as its console. 68EM.TXT This file - it describes the usage and other things present within this version of the M6800 emulator. 68EM.PIF Windows information file to get this emulator to run in a window. 68EM.ICO Icon for emulator to suit Microsoft Windows V3.0. MIPS.o68 Runs through a general selection of M6800 instruction 65535 times. By timing this an indication of the instruction through-put can be calculated. See Appendix D TASM68.TAB M6800 opcode table suited to SPEECH TECHNOLOGY INCORPORATED (C) tasm22 table driven cross-assembler version 2.2 AS0.EXE M6800 assembler from Motorola as freeware software. AS0.DOC Document for the Motorola assembler. MAIN.S19 Sample multitasking operating system that will run under the control of the this CPU emulator. MAIN.DOC A brief description of the sample operating system (MAIN.S19) and how to use it. Note that the cross-assembler by SPEECH TECHNOLOGY INCORPORATED has not been included. Their program can be acquired from any BBS that has it and will most likely be named as TASM22.ARC Notes on how to use TASM will come with the archive file. Also see the section in this document on "Extra instructions" for extra details concerning the cross- assembler in relation to this program. DISPLAY TYPE There is nothing very special about the way in which the debugger or Emulator will display its data to the console. That is there are no fancy windows or graphics included to improve the overall look of things. But rather the output is simple. There is, however, a need to setting certain things such as high brightness characters, a limied number of cursor addressing movements and clearing the whole screen. For these I have catered for two environments on which this program could run. The first is the standard "run of the mill" IBM-PC-xt/at with what ever graphics card being used. The second is for a IBM-PC type computer that runs the same programs but uses a VT-100 character terminal as its console. These do exist (I've got one!) and therefore I have adapted the program to suit them too. In fact if the standard XT/AT were to have the device driver ANSI.SYS installed then there would be no problems in running the later program on either machine. I have thought about using a soft switch within the command line when the program is invoked to indicate which console type is being used but decided against that, at least for the moment, to opt for two programs. One setup for a standard console using graphics cards and the other being setup up for VT-100 consoles. It is no big deal to do this as all it requires is one variable to be changed within the source at assembly time. The main reason for this approach is to take into account those times when a programmer is fanatically working at great pace and would much rather type a simple name to start the program instead of the name and a string of softswitches. It can be discouraging to start the program in the wrong mode and wonder why all these strange characters are appearing on the screen. Anyway it remains to be seen as to whether softswitches are included or not later. But at this moment they are not. INVOKING THE EMULATOR To start the program it is a simple matter of typing its name then pressing return. The program will load and run and the command line prompt '-' will appear. If there is a data file to loaded as well then this can be done by including the data file's name after the emulators invocation name. For example C:> 68em example.o68 Will load example.o68 into the Emulators memory after it itself has been loaded and run. All of the error checking steps that are done by the 'L' command apply. If there is an error loading the file then an error message describing the problem will be printed and the loading terminated. The Emulator will return with its prompt waiting for a command but with no data in memory. If the file loaded correctly then the byte count will be displayed followed a report on the highest and lowest address data was stored at, the Emulator's signon message and then the prompt '-' on the last line. The debugger and emulator will now be ready to use. Note that the hello message after starting will contain the current version number, the initial release date and its version number and finally the current version of the program along with its release date. This should give the user an indication of what version of the program they have and whether it is as recent as it should be. After a succesful load of a data file on starting the Emulator the Program Counter (PC) and all of the default addresses used within the debuggers commands will be set to the same value as the lowest address data was stored at. This makes for a quick and easy startup of a 6800 program that will require the user to merly enter a 'G' command to start the application. DEBUGING COMMANDS In order to make the Emulator useful then there must be some way of reading and writing to the Emulators memory, tracing execution of test programs, examining or changing, registers and loading data from files which will be more than likely be output from cross-assemblers. The M6800 Emulator has these functions and they will be described here. The usual format will be: command If an 8 bit constant is required in any of the commands and a 16 bit constant was entered then only the last 8 bits will be retained. MISCELLANEOUS S Q ? * S Toggles the mode in which the emulated code will run in. Initially, after begining the emulator, the program will be executed in the 'Supervised' mode in which program execution can be stopped at any time by entering a ^C. A 'G' command will return the program back to its previous position unchanged before the interupt was encounted. By issuing the 'S' command and toggling to 'Non supervised' mode programs will run until a breakpoint or an illegal opcode is found. There is no other way to exit. Mind you though that the later mode performs 3 times better than the 'Supervised' mode. The use of either mode will be determined by whether you trust the code or not. If a program is running in unsupervised mode and a control-c was entered at the keyboard then this character will be passed onto the internal keyboard buffer ready to be read by the 6800 program through the CHINT A instruction. This will allow for a reasonable emulated environment for the 6800 program to work in. That is: a control-c will be allowed to be processed by the program as if it was on its target machine. * Q Quit from the Emulators debugger and return to DOS. The return code given to DOS will be $00. * ? Prints the quick help menu to the console. SETTING CPU REGISTERS R R A < 8 bit constant> R B < 8 bit constant> R X <16 bit constant> R S <16 bit constant> R P <16 bit constant> R F < 8 bit constant> * A, B, X, S, P, and F As with any M6800 CPU chip there are five user registers which can be changed under program control and as such they can be modified at anytime through the use of the above commands. The Flag register, although not ideal for storing data in, can have it's contents changed too. This would most likely be used to set up key situations which would test program integrity at a point without the need to execute code before it. 'A' - sets the A accumulator 'B' - sets the B accumulator 'F' - sets the status flags 'X' - sets the index register 'S' - sets the stack pointer 'P' - sets the program counter * R Without a register name will print the entire register list along with the disassembly of the next instruction. Note that if a register name is given of which the program does not understand then the register list will be printed instead of an error message. A print of the register list will have the flags printed as a hex number and a single letter description of each flag bit, the contents of the five other CPU registers that are relavent to the M6800 CPU, and a disassembly of the next instruction to be executed. A typical register list would look like this: F - FF - - H I N Z Ov C A = 12 B = F7 X = 0147 S = FFF8 PC = 0100 0100 86 45 LDA A,#$45 -_ The Flags list mean: H - Half carry flag I - Interupt enable flag N - Sign bit flag Z - Zero flag Ov - Overflow flag C - Carry flag MEMORY MODIFING C E
* C The 'C' or 'fill memory with Constant' command will, by default, fill all of the Emulators 64K memory space with $00. Thus the work space can begin from a clean slate. If a start address is given, as the only parameter, then it and the following 256 bytes of memory will be set to null, $00. If a start address is given with an end address but with no constant then that area of memory within the start-end address will be filled with nulls, $00. But if a constant is supplied that range of memory will be filled with that constant. For example : C 100 200 01 will fill the address range from $100 to $200 with $01 which are "nop's". * E 'E' or 'memory Examine' and change will allow single steps through the Emulators memory space. At a point where a byte is to be changed then a new value can be entered, or a string of new data can be entered each seperated by a space character. When the [return] is entered then that data is stored to memory and the next unused address is displayed ready for new data. To exit this mode a '.' with no other data on the line should be entered followed by a [return]. Example: -E 100 0100 00 > _ will be the response. Entering data will be like this: 0100 00 > 01 02 03 04 [return] 0104 34 > _ with only a [return] on the input line then the address being looked at will increment by one. 0104 34 > [return] 0105 31 > _ To exit now just enter '.' [return] 0105 31 > . [return] -_ MEMORY DISPLAY U Z D H * D * H Dump or Hex dump will both do the same thing; print a block of data using byte size data along with it being printed as an ASCII character as it would appear on the screen. After using many different types of debuggers some use 'D' for this function and others 'H'. When changing from one to the other more than likely 'D' will be entered instead of 'H' and visa-vers. So I've included these two to do the same thing to accommodate for my limitation at least. The default block dump size is 256 bytes but if an end address is given then the hex dump will end at the end address. Note that both the start and end address will be rounded off to the lowest 16 byte field. That is $102 will be taken as $100, $159 will be taken as $150 etc. The output will be: address, 16 bytes of data, ASCII field As an example: -D 100 110 0100 - 01 02 03 04 34 31 0 45 20 10 11 13 45 48 2a 20 .41.E ...EH* -_ will result. Note that all unprintable characters will appear as a single '.' in the ASCII field. * U Uncompile will disassemble a section of code from the M6800's memory. The default listing length will be 16 lines of disassembly but given a start and end address then the disassembly will continue until the end address has been reached. If only a start address was supplied then the disassembly will print 16 lines of disassembly from that address. If an address of an instruction appears in the breakpoint list then that line of disassembly will be highlighted to make easier viewing of the code and the breakpoints position within it. The disassembler follows the usual rules concerning the M6800 instruction set as it appeared on the day. But there is one exception to the rule. When printing an instruction that uses INDIRECT addressing mode then the disassembly will have 3 parts to its opcode field. For example: LDA A 2,X will appear as LDA A,2,X Most assemblers will not accept this kind of notation but in preference for neatness I have opted for this instead of the alternatives. Motorola had changed the Mnemonics somewhat to accommodate for this problem it seems by using LDA or LDB in the 6809 series rather than LDA A or LDA B. * Z This command will print the last twenty executed instructions that the emulator has just worked on before exiting the 6800 program. The very last instruction printed, which is more than likely to be the cause of the exit, was the last instruction processed. The purpose of the command and instruction tracing will be seen when you are trying to find a reason to why a program has become a "run-away". Or why a program sourced by someone else always exits without performing anything useful. It should be pointed out that no instruction tracing will be performed when the emulator is running in unsupervised mode. In fact not much is done eccept 6800 instruction execution in this mode. All of the goodies are done in the supervised mode. Also when a program is run in unsupervised mode the instruction trace buffer is cleared thus to issue a "Z" command after a program has been executed the buffer will be reported as empty. This happens even if it was full before execution in unsupervised mode. PROGRAM EXECUTION G T B <#>
P Executing any M6800 program is simply a matter of loading the opcodes and data into the Emulators memory then instructing the emulator to take control. Three instructions are provided to help do this. Their usage desription follows. * G Goto will cause the execution of M6800 instructions from the address '' if given or from the current value contained within the M6800's Program Counter (PC). The command line address will always override the PC's current state. If at anytime the Emulator tries to execute illegal instructions then the CPU's current state will be saved and program execution ceased. A message will then be printed and the program returned back to the command line entry level. To gain an understanding of what the CPU's current state was use the Register command. See the 'R' command for usage description. * T Causes the Emulator to trace 'n' instructions at a time then return back to the command level. The default value for 'n' is one (1) but can contain values upto 255. This will make it easy to get passed those loops that might be contained within the program under test. The actual execution address is read from the CPU's Program Counter (PC) and instructions taken from there. There is no provision for overriding the Program Counter within this command. The current state of CPU is saved away for viewing later and control returned to the command level. If illegal instructions are encountered then the Emulator performs the same abort sequence as described in the 'G' command. * B Breakpoints set or cleared within the M6800 program. Upto eight breakpoints can be set at any one time and the list will be shown when the 'B' command, alone, is entered. If a breakpoint number is given but no address stated then that breakpoint will be cleared from the list and finally if an address is given with a breakpoint number then it will be set; or changed if that breakpoint number already exists. Note that a breakpoint address of the value of $FFF8 will clear the breakpoint from the list. I have used this value instead of the usual $0000 to indicate cleared breakpoint. Why? Because those values contained at the address $FFF8 - $FFFF are autovectors for interupt control. They are never instructions, or if they are then the function of the M6800 could be eratic at times. As there are no interupt functions other than a software interupt, built into the Emulator then it would be reasonable to use this as a sort of null value or useless address and in this case 'no breakpoint'. * P Will cause execution of the next instruction to completion. If it happens that the next instruction is a subroutine call then the subroutine will be executed and allowed to complete and return to its caller. At this point the program execution will stop and the register list will be printed as would any trace command do. This command is extremely useful in step over those subroutines that have been tested and proved working. Thus preventing worthless tracing of code that has been verified. SETTING INTERUPTS I I N I I * I The M6800 emulator version 0.3 and up all support interupt handling for all of the interupt types supported within the M6800 CPU. Versions before 0.3 only catered for the Software interupt. In order to implement the other two interupts other than reset this command exists. Note that when an interupt is to occur the service routine address is read from the NMI and IRQ vectors at $FFFC and $FFF8 resepectively. Entering "I" with no parameters will print the status of the registers that will keep track of when Non Maskable and Maskable interupts should occur. The mechanism for determining when either of the interupts should be invoked is by instruction count rather than an external signal of some type. Therefor you will have to work out how many instructions the target CPU will execute before the next interupt will occur. This is by no means the best answer to interupt servicing for all target environments but at least it does give you the user a way to test if an interupt service routine will work with the reset of the program. For those instances that required regular interupt signals such as 20 millisecond clocks in real time can be tested using the interupts within this emulator. As the speed of the system that this Emulator will be run on varies from system to system calculation of the instruction count per 20 milliseconds will differ and assuming you want the program under development to appear as real as posible in real time then the Emulator speed has to be worked out. (See Appendix D for more information on this) The interupt priorities appear as they would in the real thing. That is NMI has the most priority, then the IRQ interupt that will occur only if the interupt mask in the status flag is clear. An IRQ interupt can not interupt an interupt service routine already in process, whether it be a NMI or IRQ service routine running. But a NMI can interupt a IRQ or NMI service routine in process. Here lies a danger that is not protected against. If the NMI instruction count is set to a value lower than will allow a NMI service routine to finish to completion and return on the first interupt then nested interupt servicing will occur and before long the whole memory space will be overwritten by the stack thus destroying the users program. * I N Loads the Non Maskable Interupt instruction count register with a constant. If the constant was equal to $1000 then the program will be interupted by a NMI every 4096 instructions executed. * I I Loads the maskable interupt request register (IRQ) with the value constant. If the constant was $200 then the IRQ interupt will occur every 512 instructions but only if the interupt mask is clear. LOADING FILES L * L Load file from disk of the filename will cause the debugger to attempt to load data from a mass storage device. But before this can occur four checks will be done. (1) The filename's extension string will be checked for one of eight types. They are: .S1 .S2 .S3 .O80 .O68 .HEX .COM .EXE If the extension string does not match with any of these then an error message is printed and the function terminated. (2) An attempt to open the file proceeds. If this cannot be done for some reason then the reason is displayed and the function terminated. (3) If the file is of type .COM or .EXE then a straight binary load is performed and load exits. But if it is anyone of the other type of files then the debugger will interpret what type of format the data is stored as then decode and store it into the Emulators memory. The format is determined by the data contained in the file. Any one of the Motorola formats or Intel hex format can be read. As these follow strict layouts then the type can be determined and the data checked against checksum values. After the end-of-file signature has been found the debugger exits from loading the data. (4) If this is a load on entry to the emulator. That is a filename was stated in the command line at startup. Then the program counter (PC) will be set to the lowest address data was stored at. All default values within the debuggers commands will also be set to reflect the contents of the PC. If no filename is given then the last used filename will be used. That is assuming a file has been loaded within the same session. After a succesful load has been completed the lowest and highest address that had data stored to it from the source file will be displayed. This will help in determining where that run-away data went. More detailed information on the format of any of the Hex formats can be found in APPENDIX B and APPENDIX C. These should describe it sufficiently enough. EXTRA INSTRUCTIONS One of the great advantages that came with writing this emulator is that of creating my own instructions. Athough the instructions that have been added to the MM6800- Emulators repertoire are simple ones it is not unreasonable to include instructions that are very complex in there nature. That would mean that a Float Point Unit could be emulated along side the M6800 CPU with the intention that this FPU chip will be included into the final system. All aspects of the two chips could be tested. Albeit at the software level only. FPU functions have not been implemented in the MM6800- Emulator but instructions a little more basic have. These are supplied as an interface to the IBM-pc's hardware and console. Their purpose is to allow information to be displayed by the M6800 code to the user under its own control rather than the interuption of processing by the debugger. Four other instructions for reading and writting to the IBM-pc's input/output ports are supplied also to allow I/O chips to be used and controlled under the M6800 program. If ever you have had to develop programs for micro-controllers that look after the up-keep of peripherals, and there is no way of doing this in the development system, it can be frustrating. Its never quite known for sure whether the perihperals' registers have been set right. Even a bit of real time, real world, implementation could be undertaken using the IBM-pc's I/O ports. In the end it's all up to the developer as to how testing is implemented. And if you wish to use these extra instructions then by all means do so that's what they are there for. There are however two protection mechanisms included to prevent these opcodes from being included into the target systems environment and these appear in the debugger's Uncompile command and at the Cross-assembler's level. The Uncompiler will show the extra instruction by displaying them in brackets like this 0100 41 (CHOUT A) And the assembler will have to have a mask value set within the invocation command line to cause the instructions to be assembled correctly. Normally the mask will default to a value that will not allow these instructions to be assembled and an error message displayed. The command "tasm -68 test.asm" will not assemble the new instructions into the final program and if they are present will cause error messages to be printed. The command "tasm -68 -x1 test.asm" will assemble the new instructions successfully into the output. With all this said it only remains that the instructions be listed. But be aware that none of them affect the status flags of the CPU. Unlike most register modifing instructions within the M6800 standard instruction set. Character output to console CHOUT Operation: ACCX -> IBM-pc-xt/at standard output Description: The 8 bit value taken from the A or B accumulator will be sent to the standard output device of the host computer. Condition Codes: None Addressing format: Immediate. +-----------+-----------+-----------+---------------------+ Addressing | Execution | Number of | Opcode description Modes | time | bytes | HEX +-----------+-----------+-----------+---------------------+ A IMM | Undefined | 1 | 41 +-----------+-----------+-----------+---------------------+ Example: LDA A,#'e' CHOUT A ;PRINT 'e' TO STANDARD OUTPUT Character input from console CHINT Operation: ACCX <- IBM-pc-xt/at standard input Description: An 8 bit value is read from the standard input of the IBM-pc-xt/at and stored into the accumulator defined within the instruction Condition Codes: None Addressing format: Immediate. +-----------+-----------+-----------+---------------------+ Addressing | Execution | Number of | Opcode description Modes | time | bytes | HEX +-----------+-----------+-----------+---------------------+ A IMM | Undefined | 1 | 51 +-----------+-----------+-----------+---------------------+ Example: CHINT A ;READ CHAR FROM STANDARD INPUT CMP A,#$D ;CARRIAGE RETURNED ENTERED ;YET? BNE Example Read a byte from the 80x86 I/O bus IN Operation: ACCX <- (XREG) Description: The X register is placed onto the 80x86 input/output bus and an 8 bit value is read from it storing it to the Accumulator defined. Condition Codes: None Addressing format: Immediate. +-----------+-----------+-----------+---------------------+ Addressing | Execution | Number of | Opcode description Modes | time | bytes | HEX +-----------+-----------+-----------+---------------------+ A IMM | Undefined | 1 | 61 B IMM | Undefined | 1 | 62 +-----------+-----------+-----------+---------------------+ Example: LDX #$1000 IN A,X ;READ I/O PORT ADDRESS AND STORE ;THE RESULT INTO THE A-REG Write the Accumulator to the I/O bus OUT Operation: ACCX -> (XREG) Description: The X register is placed onto the 80x86 input/output bus and an 8 bit value is written to it from the Accumulator defined. Condition Codes: None Addressing format: Immediate. +-----------+-----------+-----------+---------------------+ Addressing | Execution | Number of | Opcode description Modes | time | bytes | HEX +-----------+-----------+-----------+---------------------+ A IMM | Undefined | 1 | 71 B IMM | Undefined | 1 | 72 +-----------+-----------+-----------+---------------------+ Example: LDX #$102 OUT X,A ;STORE THE A-REG TO THE PORT APPENDIX A OPCODE CONSTRUCTION Opcode b7 b6 b5 b4 b3 b2 b1 b0 | | | | | | | | | | | | | | | | | | | | -------------- Function | | | | | | ---------------------- Addressing Mode | | | | | | ------------------------------ Set selection Opcodes from $00 - $3F seem to be of no set pattern but rather allocated a random place. The other three sets of instruction, however, do follow an easy pattern. It can be considered that bit-6 determines which register will be used as follows. b6 Register selected --------------------------------- 0 A register Index register 1 B register Stack pointer The Operation that is to be perform on the SETS is contains within b0 - b3. The function is described in the SETS tables below. Each SET for each group of instructions. The instruction SETS follow: 0 - NEGate 8 - Arithmetic Shift Left 1 - illegal opcode 9 - ROtate Left 2 - illegal opcode A - DECrement 3 - COMpliment reg B - illegal opcode 4 - Logical Shift Left C - INCrement 5 - illegal opcode D - TeST 6 - ROtate Right E - JuMP 7 - Arithmetic Shift right F - CLeaR b5 b4 Addressing Mode --------------------------- 0 0 A 0 1 B 1 0 Indirect 1 1 Extended SET 2 ($40 - $7F) 0 - SUBtract Areg 8 - Exclusive OR Areg 1 - CoMPare Areg 9 - ADd with Carry Areg 2 - SuBtract with Carry Areg A - OR Accumulator Areg 3 - illegal opcode Areg B - ADD Areg 4 - AND Areg C - ComPare reg (16 bit) Xreg 5 - BIT test Areg D - Subroutine call 6 - LoaD Accumulator Areg E - LoaD reg (16 bit) Xreg 7 - STore Accumulator Areg F - STore reg (16 bit) Xreg b5 b4 Addressing Mode --------------------------- 0 0 Immediate 0 1 Direct 1 0 Indirect 1 1 Extended SET 3 ($80 - $BF) 0 - SUBtract Breg 8 - Exclusive OR Breg 1 - CoMPare Breg 9 - ADd with Carry Breg 2 - SuBtract with Carry Breg A - OR Accumulator Breg 3 - illegal opcode Breg B - ADD Breg 4 - AND Breg C - ComPare reg (16 bit) Xreg 5 - BIT test Breg D - Subroutine call 6 - LoaD Accumulator Breg E - LoaD reg (16 bit) Xreg 7 - STore Accumulator Breg F - STore reg (16 bit) Xreg b5 b4 Addressing Mode --------------------------- 0 0 Immediate 0 1 Direct 1 0 Indirect 1 1 Extended SET 4 ($C0 - $FF) APPENDIX B INTEL HEX FORMAT RECORDS The Intel Hex format data records are pretty straight forward. They are constructed with a character to indicate the record is starting ':', an address field of 16 bits, a record type field, a data field and the checksum. All of the values printed are first converted to an ASCII equivalent then sent. So to send, in the address field, a value of $4090 as a string would be '4090' but to view that number as byte values will be $34 $30 $39 $30. Each four bits have been converted to an ASCII equivalent. This applies to all values that appear within the record bounderies. Moreover the whole record is printable and any system dealing with these records will not hangup or perform strange things while trying to dump it to the serial port. +---+----+---------+------+-------------------------+----+ | : | CC | AAAA | TT | DD .. DDn | XX | +---+----+---------+------+-------------------------+----+ ':' Start of record character char 'CC' Byte count. Size in bytes of Data field. 8 bits 'AAAA' Address field. 16 bits 'TT' Record type. 00 = normal data, 01 = last record. 8 bits 'DD' Data in bytes, no spaces between any values. The data field can be of 1 to 255 bytes long. 8 bits 'XX' Checksum. 8 bits The checksum is calculated like this: Temp = CC + AA(high) + AA(low) + TT + (DD .. DDn) XX = 0 - Temp Therefore to verify a record against its checksum simply add all of the fields together and the answer should be $00 00 = CC + AA(high) + AA(low) + TT + (DD .. DDn) + XX To determine the end of the total file two methods can be used. One is to check the 'TT' field for a value of $01. But this can be a bit dubious as some programs that generate Intel hex format records don't worry about this field and leave it with a value of null, $00. The second method is to check if the 'CC' field has a null value in it. When it has then it can be assumed that no more data will follow. This seems to be the accepted way of terminating an Intel hex record. :0401000001020304F1 This Example has data in it that came from addresses $100 - $104. That data is $01, $02, $03, and $04. The Data field byte count, 'CC', is $04 and the record type is $00; a normal data record. The checksum is $F1. APPENDIX C MOTOROLA 'S' FORMAT RECORDS There are three types of 'S' format records that can be generated by a cross-assembler. Although you can be assured that the 'S1' format records will be generated by M6800 assemblers I will include the other two for completeness. These are 'S1', 'S2', and 'S3' formats. See the table below for a full layout of them but mainly the value 1, 2 or 3 indicates what size the address is in the Address field. The end of file 'S' values indicate that this will be the very last record within that file. Nine times out of ten 'S9' will be used in all cases but it is a good idea to test for all three anyway. That is assuming your loader is programmed to decode all three. The construction of the record is the starting character 'S', record type, byte count, address, data field and finally the checksum. It must be pointed out that the calculation of the checksum is slightly different to that of the Intel hex format. Instead of a value of $00 when all fields have been added together $FF is the result. But this will be described in detail later. As with Intel hex records all byte quanties are of printable form so every four bits are converted to an ASCII equivalent. S0 - Data field contains name of the source file. The address field will usually be a 16 bit null, $0000. S1 - 16 Bit address field End of file -> S9 S2 - 24 Bit address field End of file -> S8 S3 - 32 Bit address field End of file -> S7 Table 1 S-format layout +---+---+----+--------+------------------------+----+ | S | T | CC | AAAA | DD .. DDn | XX | +---+---+----+--------+------------------------+----+ S - Starting character for the record Char T - Record type. 4 bits CC - Byte count. Includes address field, data field and checksum field in the count. 8 bits AAAA - Address field. For 'S1' type. 16 bits DD - Data field. No spaces between the bytes 8 bits XX - Checksum 8 bits Calculating the checksum is as follows: Temp = CC + AA(high) + AA(low) + (DD .. DDn) XX = $FF - Temp Verifing the Integrity of a record with the checksum the following should be done. $FF = CC + AA(high) + AA(low) + (DD .. DDn) + XX But for even easier checking of the record against a checksum instead of clearing the accumulator that will keep a tally of the checksum calculations start it with $01. Then when the final value, the 'XX' field, is added to the accumulator the result will be zero. Z flag gets set, no need to compare it against $FF. To further describe the 'S0' record which contains the source files name or anything else look at the example below. The source file's name is contained within the data field but each byte that makes up each letter in the source file's name 'test.asm' is taken as a byte literal and converted to printable form like any other byte to be inserted into the record. Other than that the record follows the same rules as would any other record type within the file. S0110000746573742E61736DBF <- "BF" = Checksum ---------------- ^------------ Source filename 'test.asm' S107010001020304ED S9 This 'S1' record has in it data from addresses $0100-$0104 of the value $01, $02, $03, and $04 the data field is 'CC' - 3 (ie: $07 - $03) = $04 and the checksum is $ED The next line has on it an S9 which indicates the end of file. APPENDIX D PERFORMANCE To calculate the speed at which the Emulator is processing M6800 instructions run the program MIPS.o68 with supervisor mode turned off (use 'S' command) and begin execution with 'G 100 [return]'. At the same time start timing with your trusty time-piece until an illegal instruction exception is reported. Stop timing. This value is now time. Now put the value time through the following formulae to get instruction through-put (IPS) and equivalent clock speed (clk) that a real M6800 cpu would have to be running at to equal the performance of the Emulator. IPS = (3 + (46 * 65535))/time (seconds) clk = (9 + (152 * 65535))/time (seconds) Here are some figures that I have gained from various test machines. All IBM-pc compatable. 80386 @ 20MHz. Time = 25.3 seconds Calculated: IPS = 119,154 Instructions per second. Calculated: clk = 393,728 Hz M6800 cpu. 80286 @ 12 Mhz. Time = 37.8 seconds Calculated: IPS = 79,751 Instructions per second. Calculated: clk = 263,527 Hz M6800 cpu. 80286 @ 8MHz. Time = 64.7 seconds Calculated: IPS = 46,593 Instructions per second. Calculated: clk = 153,962 Hz M6800 cpu. 80186 @ 10Mhz. Time = 65.1 seconds Calculated: IPS = 46,307 Instructions per second. Calculated: clk = 153,106 Hz M6800 cpu. 80c86 @ 9.5 Mhz. Time = 81.3 seconds Calculated: IPS = 37,080 Instructions per second. Calculated: clk = 122,525 Hz M6800 cpu. 80c86 @ 4.77Mhz. Time = 163.3 seconds Calculated: IPS = 16,855 Instructions per second. Calculated: clk = 61,000 Hz M6800 cpu.