home *** CD-ROM | disk | FTP | other *** search
- AMYX DEBUG ABSTRACT
-
-
- This abstract is provided to help you find your way through AMYX
- DEBUG without having to tough out all the logic on your own. It
- is not intended to be a byte-by-byte theory of program operation.
- The source code is adequately commented to reveal all the nitty-
- gritty details. Major program divisions are indicated by cen-
- tered headings; the routines or subroutines they include are in-
- dicated by the capitalized routine names followed by a colon, in
- the usual assembler label fashion.
-
- Once DEBUG is activated, it is, in essence, just a menu-driven
- program, with the "menu" selection made through the entry of a
- command letter. When the command is decoded, a jump is made to
- the selected routine. When the command action is finished, the
- program returns to the "Command?" prompt and waits for another
- command entry.
-
-
- DEVELOPMENT/MODIFICATION
-
- While AMYX DEBUG was developed on (and for) a Kaypro 4-84 Plus
- 88, it was deliberately designed to make maximum use of standard
- CP/M calls so that it could easily be transported to any CP/M
- based computer with an 80 x 24 screen display and a means of dis-
- crete screen cursor positioning. The program source code uses
- only standard Z80 mnemonics (except for the 'TITLE' peculiar to
- Micro Cornucopia's CROWECPM) and should be compatible with any
- standard Z80 assembler. The use of a macro assembler is not
- required.
-
- The only real "customization" necessary for non-Kaypro computers
- should be in the screen cursor positioning subroutine POSCUR.
- This subroutine can simply be rewritten in its entirety as re-
- quired. The Kaypro cursor positions indicated by equates in the
- data section of the program are as follows (screen "home" at line
- 0, column 0):
-
- COMCUR: cursor position for "Command?" prompt.
- 3720H = line 23, column 0
- ERRCUR: cursor position for error messages.
- 3742H = line 23, column 34
- BRKCUR: cursor position for breakpoint display.
- 3520H = line 21, column 0
- MODCUR: cursor position for modify memory prompt.
- 3729H = line 23, column 0
- MEMCUR: cursor position at beginning of memory display.
- 2D26H = line 13, column 6
-
- The only other Kaypro specifics are the clear screen character
- (26D) and the cursor "home" character (30D).
-
- The highest address of relocated code is specified in the equate
- RELTOP:, located just at the end of the relocation and initiali-
- zation module; the highest relocation address is actually set at
- RELTOP-2 by calculations located at the very end of the program
- code. RELTOP is currently set at E000H, the bottom of the CCP
- for the Kaypro 4-84; RELTOP can be changed to any reasonable val-
- ue without making any other changes in program code.
-
- DEBUG object code has successfully been transported directly to
- an older Kaypro II.
-
-
- GENERAL PROGRAM ORGANIZATION
-
- Briefly, DEBUG is organized as follows:
-
- RELOCATION AND INITIALIZATION
- BEGIN DEBUG CODE
- BIOS equates
- Character equates
- Cursor positions
- Messages
- Variables
- --MAIN PROGRAM--
- ENTRY: Entry
- ENTRY0: Screen display
- COMAND: Command entry
- COMDEC: Command decode
- COMMAND ACTION
- MPAGE: Page memory forward or back
- DSPLAY: Display selected page of memory
- MODMEM: Modify memory
- BRAKPT: Set breakpoint from keyboard entry
- SSTEP: Single-step
- CLRBRK: Clear all breakpoints
- FIXBRK: Clear specified breakpoint
- JUMP: Jump to specified address
- FILL: Fill memory with specified byte
- REGMOD: Modify register contents
- MOVE: Block move
- SEARCH: String search
- HARITH: Hex arithmetic
- DBEND: Return to user program
- DEBUG-SPECIFIC SUBROUTINES
- DISPAF:/DPRIM: Display contents of CPU AF and AF' registers
- DISPBC:-DISPPC: Display contents of all other CPU registers
- DISMEM: Display contents of 128-byte page of memory
- REGRET: (Calls ONLYRG and DISRG)
- ONLYRG: Display just the contents of a CPU register
- DISREG: Display the register indirects
- DISBRK: Display breakpoint addresses
- GETWRD:/GETBYT: Convert ASCII command buffer data to hex
- values
- NXTCHR: Adjust command buffer pointer and counter when
- decoding a command
- COMCHK: Check for bad command
- COMCH1: Print error message and cancel command
- SETBRK: Install breakpoint in user program code
- MATCH: Search breakpoint table for address
- LOAD: Fill memory with specified byte
- REPBRK: Repair breakpoint set in user program code
- GENERAL SUBROUTINES/PRIMITIVES
- GENRET: Return for several subroutines
- KBD: Strobe keyboard for one character
- CHROUT: Print one character on screen
- MSGOUT: Print string on screen
- HX2ASC: Convert one hex byte to ASCII and output to screen
- ASC2HX: Convert one ASCII character to a hex value
- NEWLIN: Drop cursor one screen line
- POSCUR: Place screen cursor at specified position
- BEEP: Beep keyboard
- DELAY: Delay approximately three seconds
- TABLES
- STACK
-
-
- RELOCATION AND INITIALIZATION
-
- Relocates the DEBUG code from CODBEG: through CODEND: with the
- highest program byte one address below the address specified by
- the equate RELTOP:. All breakpoints are cleared; the jump to the
- relocated CODBEG: address is written into the DDT call address at
- 38H; a loaded-and-relocated confirming message is printed on the
- screen, together with the addresses that the relocated DEBUG oc-
- cupies; and system control is returned without a warm boot.
-
-
- DEBUG CODE
-
- Actual DEBUG code, starting at CODBEG:, follows the relocation
- and initialization section. The only action that takes place at
- CODBEG: is a jump to ENTRY:, where the main program starts. Be-
- tween CODBEG: and ENTRY: are located BIOS equates, character
- values, cursor positions, messages, and variable allocations.
-
-
- MAIN PROGRAM
-
- ENTRY: is where the action starts. First, the user SP is saved
- and the DEBUG stack address is loaded into SP; then the user's
- register contents are pushed onto the DEBUG stack. The user PC,
- placed on the user's stack by the RST 38H DEBUG call, is stored,
- then popped off the user's stack and discarded. The user's cur-
- sor location is also saved in case the user's program includes
- direct screen manipulation. DEBUG then checks the breakpoint
- table (BRKTBL:) to see if any breakpoints are set and, if so,
- installs them in the user program code.
-
- A check is then made to see whether entry to DEBUG came from an
- RST 38H coded into the user program or from a breakpoint. This
- test is made by decrementing the user PC (SYSPC:) and testing
- that address against entries in the breakpoint table (BRKTBL:).
- (The RST 38H places the next program address on the stack as its
- "return" point.) If no match is found, DEBUG execution jumps di-
- rectly to ENTRY0: to write the screen display. If entry is from
- a breakpoint, the user code is repaired (see SETBRK: and REPBRK:)
- and the decremented PC is retained as the actual PC to resume ex-
- ecution of the user program.
-
-
- OPENING SCREEN DISPLAY
-
- At ENTRY0: the screen is cleared of whatever the user might have
- had on it; at ENTRY1: the writing of the DEBUG display begins.
- When the screen display is complete, the program jumps to COMRET:
- (located after the last command processing section), then to
- COMAND: for command entry.
-
-
- GENERAL PROGRAM FLOW
-
- Once DEBUG is invoked, the opening screen display is complete,
- and the "Command?" prompt is written, the general program flow is
- as follows:
-
- --Check for immediate commands. Immediate commands are
- acted upon as soon as their character is entered.
-
- --Enter characters into the command buffer. All charac-
- ters are checked to be sure they're valid as they are
- entered. Valid characters are added to the command buf-
- fer (COMBUF:); invalid characters are signaled by a key-
- board beep and a stationary cursor. All commands (except
- immediate commands) are terminated with a carriage re-
- turn, which is NOT added to the buffer.
-
- --Decode the command. As soon as the first character in
- the command buffer is checked to see what it is, a jump
- is made to the indicated command section. The remainder
- of the command line is decoded in the command sections
- according to the command's requirements. After decoding,
- all commands are checked (COMCHK:) to be sure the correct
- number of characters was entered (i.e., a coarse check to
- be sure that all addresses and byte values are complete).
-
- --Carry out the command.
-
- --Return to the command line. All command action is ter-
- minated by a jump to COMRET:, where the command entry
- line is tidied up and flags are cleared, followed by a
- jump to COMAND:, where the buffer counters are reset and
- the "Command?" prompt is written.
-
-
- COMMAND PROCESSING MODULE
-
- COMAND: is where the program lands upon completion of the opening
- display or at the end of any command action. KEYIN: and KEYIN1:
- begin the keyboard strobe loop to pick up characters. Input
- characters are checked first to see whether they're immediate
- commands. If so, they are acted upon immediately; if not, the
- first character is checked to be sure it is a valid command. The
- command character is also stored in COMFLG: as an indicator that
- a command is in progress. Characters after the first one are
- checked in CKCHAR: to be sure that they're a hex digit, a regis-
- ter specifier, a period, a space, a backspace, or a carriage re-
- turn. Valid characters are added to the buffer in AD2BUF:, with
- the buffer pointer and character counter adjusted appropriately.
- Spaces are valid characters from the keyboard, but are not added
- to the command buffer. Invalid characters cause a jump to
- BADCHR: for a keyboard beep and cursor backspace. AD2BUF: and
- BADCHR: terminate with a jump to KEYIN1: for the next character.
- Entry of a carriage return (which is not added to the command
- buffer), sends program execution to COMDEC:, where the command is
- decoded.
-
-
- COMMAND DECODE
-
- COMDEC: begins decoding of the command. As soon as the command,
- the first character in the command buffer, is identified, program
- execution jumps to the indicated section. Command data are de-
- coded within each command routine, mainly by GETWRD: and GETBYT:,
- subroutines that translate the command buffer ASCII characters
- into hexadecimal values.
-
-
- PAGE MEMORY FORWARD OR BACK (IMMEDIATE COMMAND)
-
- MPAGE: adds or subtracts 80H from the value saved in MEMSEL:, the
- area of memory selected for display, saves the new value in
- MEMSEL:, then rewrites the page of memory on display through a
- call to DISMEM:.
-
-
- MODIFY MEMORY
-
- MODMEM: begins the routine for modifying memory. This routine is
- initiated by the usual command format. Use of the modify routine
- is indicated by setting the byte MODFLG: to 1, after which the
- addresses to be modified are automatically incremented and dis-
- played with a "Modify: AAAA" prompt, and all the user enters is
- the new byte for the address. This subsequent modification is
- carried out through a loop from MODME1: to the end of MODME2:,
- and is terminated by the entry of a period in place of a byte
- value.
-
-
- SET BREAKPOINT FROM KEYBOARD ENTRY
-
- BRAKPT: begins the routine to set a breakpoint from keyboard en-
- try. Setting a breakpoint involves two steps. First, the break-
- point table (BRKTBL:) is checked to see if there's room for an-
- other breakpoint (indicated by a 0000 entry). The first 0000 en-
- try encountered is filled in with the address specified by the
- user. If no empty space is found, the keyboard beeps, the mes-
- sage "BREAKPOINTS FULL!" is displayed, and the program returns to
- COMAND:. Second, the breakpoint is installed in the user program
- code through a call to SETBRK:.
-
-
- SINGLE-STEP
-
- SSTEP: begins the single-stepping routine. The gist of single-
- stepping is to emulate CPU action through software one step ahead
- of the CPU, setting a breakpoint at the executable instruction
- following the one shown at the PC. Single-stepping is effected
- through four separate actions.
-
- First, the code at the user PC must be discretely tested for
- jumps (SSTEP:-SSTE17:). If the next executable instruction is an
- unconditional jump, a breakpoint is set internally at the jump
- address. If the next executable instruction is a conditional
- jump, the contents of the F register must be tested. If the jump
- condition is true, then a breakpoint is set at the jump address.
-
- Second, if the jump condition is not true or if the instruction
- is not a jump, then the length of the instruction at the current
- user PC must be determined. The length of the instruction is de-
- termined by comparing the byte at the PC, and the one following,
- if necessary, with the contents of tables TAB21:, TAB22:, TAB31:,
- TAB32:, and TAB42: (located at the very end of the program code).
- Bytes in tables TAB21 and TAB31 are single-byte indicators of
- two- and three-byte instructions respectively. If the byte at
- the PC is DD, ED, or FD, then the bytes in tables TAB22, TAB32,
- and TAB42 indicate two-, three-, and four-byte instructions re-
- spectively. A byte at the PC not found in the tables is assumed
- to be a one-byte instruction.
-
- Third, after the length of the instruction has been determined,
- the user PC address is incremented accordingly to establish the
- address of the next executable instruction. Fourth, the address
- of the next instruction is stored in the first breakpoint table
- location (overwriting anything that might have been there) and a
- breakpoint is installed at that address using SETBRK:.
-
-
- CLEAR ALL BREAKPOINTS (IMMEDIATE COMMAND)
-
- CLRBRK: starts the routine for clearing all six breakpoints. The
- breakpoint table is tested for entries. Where a nonzero entry is
- found, the breakpoint is repaired using REPBRK:. After the
- breakpoint is repaired, its entry in the breakpoint table is set
- to zero. When all breakpoints have been cleared, the breakpoint
- display line is rewritten to show its cleared status.
-
-
- CLEAR A SPECIFIED BREAKPOINT
-
- FIXBRK: clears one breakpoint specified by the user. The user's
- entry is checked against the breakpoint table, and a BAD COMMAND!
- message is posted if there is no match. If the specified address
- is ok, its table entry is set to zero, the breakpoint is repaired
- using REPBRK:, and the breakpoint display line is rewritten to
- show its new status.
-
-
- JUMP TO SPECIFIED ADDRESS
-
- JUMP: directs execution of the user program to the specified ad-
- dress. The specified address is loaded into the user's PC stor-
- age area; DEBUG then executes a "Go" through a jump to DBEND:
- (control is returned to the user program).
-
-
- FILL MEMORY AREA WITH SPECIFIED BYTE
-
- FILL: simply fills an area of memory from a specified starting
- address through a specified ending address with a specified byte.
- FILL: sets up the starting and ending addresses; the actual load-
- ing of memory is done in the subroutine LOAD:.
-
-
- MODIFY REGISTER CONTENTS
-
- REGMOD: starts the routine to modify the contents of a specified
- register. What's actually changed is the user register value
- stored on the DEBUG stack. The new value is loaded into the
- specified register only when a Jump or Go is executed and the
- contents of the stack are popped back into the registers.
-
- First, the register identifier in the command buffer is "hashed"
- by adding the ASCII values of the two characters together. Be-
- cause the user SP and PC are not stored on the DEBUG stack, a
- discrete test is made for them first. If the register to be mod-
- ified is neither SP nor PC, the test for which regular register
- is made by using a CPIR instruction to compare the hashed identi-
- fier value with the possible hashed identifier values, which are
- in table REGTAB: (at the end of the program). If no match is
- found, the program jumps to BADREG: and outputs the BAD COMMAND!
- message.
-
- If a match is found in the table, the contents of the C register
- at the match are used to calculate the location of the register
- on the stack from the current DEBUG SP. If the register to be
- modified is SP or PC, dummy displacements of FFH and FEH respect-
- ively are used to so indicate. The indicated change is made in
- memory, then the whole screen display is rewritten to show the
- new register status.
-
-
- BLOCK MOVE
-
- MOVE: uses the LDIR instruction to copy the contents of a block
- of memory specified by starting and ending addresses to a loca-
- tion whose starting address is specified. The routine calculates
- the number of bytes to move from the starting and ending address-
- es, registering an error if start and end have been entered
- backward.
- STRING SEARCH
-
- SEARCH: searches an area of memory specified by a starting and
- ending address for a string defined by hex values. The length of
- the input string is limited only by the size of the command buf-
- fer. Because the command requires two bytes (ASCII characters)
- per hex byte of data, the maximum string length turns out to be
- 11 bytes. Because the length of the string is variable, its end
- must be marked by a period. If no period is found when decoding
- the command buffer, an error is registered.
-
- The search algorithm itself runs from SEARC8: through the end of
- SEARC5: If the string is not found, the program jumps to SEARC6:
- and outputs a STRING NOT FOUND message. If the string is found,
- the program jumps to SEARC7:, where the address of the first
- character of the find is loaded into MEMSEL: as the address of
- the page of memory to be displayed, and the memory display is re-
- written. Additionally, if the string is found, the search can be
- resumed for further searching in the specified area of memory by
- entering S followed by a period. In this case, the search starts
- again with the first address following the last character of the
- last find.
-
- The little subroutine ENDTST: following the string search routine
- is unique to SEARCH: and was placed here to keep it from getting
- lost in the chaff of other little subroutines.
-
-
- PERFORM HEX ARITHMETIC
-
- HARITH: just performs sixteen-bit hexadecimal addition or sub-
- traction and prints the results on the command line following the
- input. The result of a calculation remains on display until any
- key is pressed.
-
-
- RETURN TO COMMAND LINE
-
- COMRET: is the location to which all commands jump when their
- action is completed. In COMRET:, the command line is blanked and
- the flags MODFLG: (which indicates that a modify memory command
- is in process) and COMRET: (used in testing for immediate com-
- mands to indicate that any command is in process) are turned off
- (set to zero). The program then jumps back to COMAND: to await
- input of the next command.
-
-
- RETURN TO USER PROGRAM
-
- DBEND: is the "end" of the DEBUG program; that is, a jump to
- DBEND: from either a Go or a Jump command (or a Go internally ex-
- ecuted in single-stepping) returns control to the user program.
- The user's cursor position is restored, the user's PC is returned
- from storage to the bottom of the user stack, all registers are
- popped from the DEBUG stack, the user stack pointer is loaded in-
- to the SP register, and a RETurn is executed.
-
- DEBUG-SPECIFIC SUBROUTINES
-
- DISPAF:/DPRIM: prints the AF and AF' register displays on the
- screen. On entry, IX contains the DEBUG SP. A, E, and HL are
- destroyed.
-
- DISPBC:-DISPPC: print the displays for the indicated registers by
- loading HL with the register contents from the DEBUG stack and
- then jumping to REGRET:. On entry, IX contains the DEBUG SP.
-
- DISMEM: prints the 128-byte page of memory in the display. On
- entry, the address of the selected area of memory for display is
- in HL. A and BC are destroyed.
-
- REGRET: is the common return from all the register displays. It
- makes two subroutine calls to ONLYRG: and DISREG:.
-
- ONLYRG: prints the contents of a Z80 register to the CRT screen.
- On entry, the hex word to be output is in HL. A and E are
- destroyed.
-
- DISREG: prints the sixteen indirect address contents for the reg-
- ister displays and the memory display. On entry, the address for
- which the indirects are to be displayed is in HL. A, BC, and E
- are destroyed.
-
- DISBRK: prints the breakpoint line on the display. Nothing is
- transferred in through CPU registers; uses A, B, DE, and HL.
-
- GETWRD:/GETBYT: decode a two-byte hex word or a hex byte from the
- ASCII representations in the command buffer. On entry, the cur-
- rent address of the command buffer pointer (COMBUF:) is in HL.
- GETWRD: returns the hex word in DE; GETBYT: returns the byte as a
- "low" byte in E.
-
- NXTCHR: advances the command buffer pointer (COMBUF:) and incre-
- ments the command buffer counter (CBUFCT:). On entry, the com-
- mand buffer pointer is in HL; the current buffer character, which
- is in A, is preserved. NXTCHR: is used primarily by GETWRD: and
- GETBYT:, but is also called directly from the main command rou-
- tines for modifying register contents (REGMOD:), for hex arithme-
- tic (HARITH:) as a way of picking up a non-hex character (the
- arithmetic operator) discretely, and by SEARCH: as a way of dis-
- carding the period ending the command.
-
- COMCHK: checks any command after decoding to be sure that the
- command contained the proper number of characters (the command
- buffer counter (CBUFCT:) should be zero after any command is
- decoded). If the command is good, only A is destroyed. If the
- command is bad, the subroutine continues on to
-
- COMCH1:, which beeps the keyboard and prints the BAD COMMAND!
- message. COMCH1: is also called any time a command error is
- detected for whatever reason (e.g., a missing period in the
- Search command entry). All registers are destroyed.
-
- SETBRK: is where breakpoints set either from user keyboard entry
- or internally during single-stepping are established. There are
- two tables involved with breakpoints, BRKTBL:, which contains the
- breakpoint addresses, and CODSAV:, which contains the bytes of
- user program code saved when a breakpoint is installed. These
- two tables are linked by a counter, BRKCNT:, to keep the bytes of
- saved code in proper relationship to the addresses where they be-
- long. On entry to SETBRK: the address of the user program where
- a breakpoint is requested is in DE.
-
- The byte of code at the breakpoint address is transferred to its
- position in CODSAV:; the breakpoint address in the user program
- is then loaded with FFH (RST 38H) to effect the breakpoint. A is
- destroyed.
-
- MATCH: searches the breakpoint table for a match with a break-
- point address requested to be cleared through FIXBRK:. On entry,
- the address to be tested is in DE. A, B, and HL are destroyed.
-
- LOAD: fills an area of memory from a specified starting address
- through a specified ending address with a specified byte. On
- entry, the start address is in DE, the end address is in HL, and
- the byte is in A. All registers are preserved.
-
- REPBRK: is just the inverse of SETBRK:. Here the breakpoint
- (FFH) in the user program is replaced with its proper code byte
- from the CODSAV: table. On entry, the breakpoint address is in
- DE. A is destroyed.
-
-
- GENERAL SUBROUTINES/PRIMITIVES
-
- GENRET: is a common return from any subroutine that pushes BC,
- DE, and HL.
-
- KBD: uses the standard BDOS call to strobe the keyboard for one
- character, shifting the character to upper case if necessary.
-
- CHROUT: uses the standard BDOS call to output one character to
- the CRT screen.
-
- MSGOUT: uses the standard BDOS call to output a string to the CRT
- screen.
-
- HX2ASC: converts a hex byte to its ASCII representation and out-
- puts it to the CRT screen. The byte to be converted is in A on
- entry; E is destroyed.
-
- ASC2HX: converts one ASCII character to its hex value; e.g., "F"
- becomes 0FH. On entry, the ASCII character is in A; on exit, A
- contains the hex value.
-
- NEWLIN: outputs a carriage return-line feed sequence to the CRT
- screen to drop the cursor a line. E is destroyed.
-
- POSCUR: positions the screen cursor in accordance with Kaypro
- protocol. On entry, the hexadecimal row,column cursor position
- is in the BC register (B=row; C=column). E is destroyed.
-
- BEEP: sends an ASCII 07H to the keyboard. All registers are
- preserved.
-
- DELAY: does nothing for approximately three seconds; used to hold
- error messages on the screen. The inner loop takes approximately
- one-half second to complete; hence, the total delay can be ad-
- justed in half-second increments by changing the value loaded in-
- to B in the first line. A, B, and HL are destroyed.
-
-
- TABLES
-
- REGTAB: contains the "hashed" identifiers (i.e., the sum of the
- ASCII values of the characters; A'=AF', B'= BC', etc.) for all
- the registers but SP and PC. Used by the modify register (REG-
- MOD:) routine.
-
- Tables TAB21:-TAB42: are used in conjuction with the single-
- stepping routine (SSTEP:) to determine the length of any instruc-
- tion. The end of each of these tables is identified by TNNEND
- with an equate at location; the beginning and ending labels of
- the tables are used to calculate the table lengths for the CPIR
- instruction in the single-step routine. I set the tables up this
- way just in case I missed a byte or the information I was working
- from was incorrect or incomplete. If a user finds an error in
- these tables, he can correct it by changing, adding to, or delet-
- ing from the tables without having to be concerned with any
- changes in program code per se.
-
- TAB21: contains one-byte indicators of two-byte instructions;
- that is, if the byte is any of TAB21:, then the instruction is
- two bytes long.
-
- TAB22: contains the second byte of two-byte indicators of two-
- byte instructions. If the first instruction byte is DD, ED, or
- FD, and the second byte is any of TAB22:, then the instruction is
- two bytes long.
-
- TAB31: contains one-byte indicators of three-byte instructions;
- that is, if the byte is any of TAB31:, then the instruction is
- three bytes long.
-
- TAB32: contains the second byte of two-byte indicators of three-
- byte instructions. If the first instruction byte is DD, ED, or
- FD, and the second byte is any of TAB32:, then the instruction is
- three bytes long.
-
- TAB42: contains the second byte of two-byte indicators of four-
- byte instructions. If the first instruction byte is DD, ED, or
- FD, and the second byte is any of TAB42:, then the instruction is
- four bytes long.
-
-
- STACK
-
- A 64-byte (32-word) stack (LOCSP:) is located at the very end of
- the program code. Inasmuch as ten stack words are always in use
- by DEBUG for the user register contents, the stack is effectively
- 22 words deep. This is probably adequately conservative. Al-
- though I haven't checked to see how deep the subroutines are go-
- ing, the limit is probably no more than eight, including PUSHes.
- I have not, in any event, found the end of TAB42 corrupted at any
- time.
-
-
- THE FINAL EQUATES AND CALCULATIONS
-
- The final equates and calculations CODEND, CODSIZ, DESTIN, and O
- all pertain to the relocation of DEBUG and the offset applied to
- jumps and calls in its relocated position. The program can be
- modified anywhere between CODBEG: and CODEND without the need for
- special attention to relocation or offsets.
-
-
- ###
-