Chapter Three - hyperSOURCE Tutorial This chapter contains a tutorial for running hyperSOURCE. It is highly recommended that you work through this tutorial, which will introduce you to the most frequently used commands and allow you to experiment with them in a controlled environment. Once you have completed the tutorial, you should be prepared to use the hyperSOURCE and MICE-III combination in your target system. Preparing to Run hyperSOURCE To execute hyperSOURCE, do the following steps: 1.Connect the RS-232 cable from the COM1 or COM2 port on your PC to the SERIAL port on the back of the MICE-III chassis. 2.Power up your PC host. 3.If you have not already installed hyperSOURCE, do so at this time. Insert the hyperSOURCE distribution diskette into drive A and type a:install. If your RS-232 cable is connected to the COM2 port on your PC, then you must edit the environment (*.env) file. Change COM=1 to COM=2. Make sure you do not use an editor that embeds control characters. 4.Power up the MICE-III and invoke USD-III. Verify that the emulator passes all power-up diagnostics properly. 5.Exit USD-III and move to the hyperSOURCE directory. 6.Invoke hyperSOURCE as shown: > hs186 ;if you have the MICE-III-80C186, MICE-IIIS-80C186 MICE-III-80C188, MICE-IIIS-80C188 MICE-III-80C186EB, MICE-IIIS-80C186EB or MICE-III-8086F > hs286 ;if you have the MICE-III-80286 Note You may also simply power on the emulator and start hyperSOURCE, but remember that when you first power up the MICE-III, it executes self diagnostics which take up to one minute to complete. HyperSOURCE will connect when these diagnostics complete. Subsequent connections will take only a few seconds to complete. HyperSOURCE Problems and Solutions NOTE: Skip ahead to the Tutorial unless you've encountered problems loading hyperSOURCE.) The following describes a few problems you might encounter with hyperSOURCE. The solutions to those problems are also described. 1. File Problems - HyperSOURCE is unable to open the necessary files. a) HyperSOURCE will quit and return control to the host operating system. This error can occur because: - The disk is full. - The maximum number of files that can be opened has been reached. You must increase the number by adding FILES=20 to your config.sys file. - You do not have write privilege in the current directory. b) HyperSOURCE is unable to load your OMF file properly. If you are using OMF files created with Intel development tools, modify the source file extension parameter in the *.env file. Refer to "Specifying Debug Characteristics" in Chapter One. 2. Host Memory Problems - The host system has insufficient or unusable memory. Use a system information utility (such as PMINFO or INFOPLUS, which are included with hyperSOURCE) to verify the host memory configuration. a) HyperSOURCE requires extended RAM, not expanded. b) HyperSOURCE conflicts with some versions of himem.sys. HyperSOURCE will initialize and appear to work, but OMF loads and other communication-intensive operations will fail. Testing with himem.sys, v2.77 which is supplied with DOS 5.0, was successful. c) Four megabytes of extended RAM should be sufficient for nearly all configurations; however, very large OMF files containing large numbers of symbols may require additional memory. 3. Communications Link Problems - HyperSOURCE cannot establish communication with the MICE-III. a) Make sure power is applied to the emulator. If not, turn the emulator on and re-execute hyperSOURCE. b) Make sure the RS-232 cable is connected to the serial port of the emulator. c) Verify that COM = 1 or COM = 2 in the *.env file matches the serial communications port on your PC. d) Make sure that the MICE-III emulator is initializing properly. Use the terminal port to establish communications with the emulator and verify power-up diagnostics. e) Make sure that target hardware is not introducing any problems. Bring hyperSOURCE up and verify operation prior to connecting to the target. f) Try using a faster PC host. Some slow PC ATs can cause communication problems with the MICE-III. g) Try eliminating unnecessary memory resident programs and device drivers from your autoexec.bat and config.sys files. For example, if you are not using a mouse with hyperSOURCE, you should remove the device driver for the mouse from your config.sys file. HYPERSOURCE TUTORIAL Once hyperSOURCE has initialized with the MICE-III, you may continue with the following tutorial. This tutorial expects a "normal" installation has been completed; i.e., that the hyperSOURCE executable, help files, *.env, and demo programs all reside in the appropriate subdirectories. If this setup has been changed, the tutorial may produce unpredictable results! This tutorial contains a C module which performs a continuous re-ordering of a linked list. Essentially it takes the fourth element of a linked list and substitutes another element into the linked list. Then the program loops, where it once again deletes the fourth element of the linked list and substitutes once again. In each one of the link list elements is an area containing a number. These numbers begin in the sequence 1, 2, 3, 5, 5. Then after the first substitution the sequence is 1, 2, 3, 4, 5. Then it changes back and forth between the two sequences forever. It calls other procedures which are contained in the module sub_func. Let's begin. -> hs186 (or hs286) Invoke hyperSOURCE if you have not already done so. ============================================================================== LOADING AND EXECUTING CODE This section of the tutorial demonstrates how to set up the emulator, load code for debugging, and execute code in various ways. -> pause off Turn off screen pause. -> map 0 0fffff e This command maps all memory accesses to the target. It's equivalent to a MAP CLEAR command, to assure that the next two commands are accepted. -> map 0 0ffff i Map 64K of internal overlay RAM from 0 to FFFF. -> map 0f0000 0fffff i Map 64K of internal overlay RAM from F000 to FFFFF. -> load demo.omf Load the realmode OMF file. -> go main Execute from the starting address to the main C function main(). We'll return and take a look at some assembly-level features later. -> e Pull down the Execution menu. Press F1 to display the help screen for the execution menu. The 'S' or Step command is your main tool, used to perform high-level steps, one statement at a time, through your code. 'S IN' or Step INto, will step into statements instead of through them. Later we will use the equivalent instruction-level commands 'IS', Instruction Step and 'IS IN', Instruction Step INto. -> s Single-step through one statement. -> s Again. -> s Again, executing the entire procedure insert(). The highlight in the Source window should now be on line #38, at the procedure printall. The highlight indicates the statement about to be executed. -> s in Step INto printall. Note the source window automatically updates to show the source for printall, part of the file sub_func. The module name and current line number appear on the barline separating Source and Dialog windows. -> s 3 Make 3 steps. Line #67 in printall should be highlighted. -> go til #72 Execute from the current PC to line #72 in the current module. The 'til' is optional. -> go til ret Execute from the current PC until a Return from subroutine occurs, i.e., a stack pop returns us to the previous scope, main(). -> b #43 We'll do more with breakpoints in a later section, but for now we need to use one to show the function of 'Go Forever'. -> go This causes the program to execute, stopping at the breakpoint on line 43. -> g for Go Forever starts the emulator without installing any defined breakpoints. Notice that the MICE EP light is on, indicating the emulator processor is running. R> mem 0 While the emulator is running, some operations are not permitted. R> b 0 #44 Ditto. R> pri However, you can dump the trace buffer. R> pri source 700 Here is the same data, the last 256 frames of the trace buffer, in source format. R> rt The trace buffer stops acquisition when you display it. The Restart Trace command, 'rt', restarts the acquisition. NOTE: The MICE-III-80286 may erroneously issue the message "Emulation processor stopped by user." This is a known error which should be ignored. Later, in the TRACE section of this tutorial, we'll set up complex triggers to trigger the trace buffer. R> macro snap You may skip this step, but this macro definition is MD>pri 7f0 presented here to give you an idea of one useful way MD>rt to use the 'pri' and 'rt' commands. MD>emac R>snap R> halt Use 'halt' to halt the emulator. Next we'll take a look at the IS, 'Instruction Step' command. This can be used in conjunction with 'View Mix' to step through code at the instruction level, but is more useful when debugging assembly level code. We'll reset the emulator and step through the assembly-level startup code. -> reset You should see the code at the reset vector. -> is The emulator executes one instruction, the JMP to _start_. -> is 10t (If using 80C186/188) is 11t (If using 80286) The emulator executes ten (or eleven) instructions. -> u Disassemble, starting at current CS:IP. Note the REP instruction about to be executed. -> is The IS command recognizes this as a "high-level" statement and stops on the other side, rather than stepping into it. This completes the tutorial section on LOADING AND EXECUTING CODE. ============================================================================== WINDOW MANAGEMENT This portion of the tutorial demonstrates the various hyperSOURCE data windows and pull-down menus, as well as their operation. -> inc setupr.inc list Use this include file to setup the emulator for the next portion of the tutorial. -> The F1 key is used to summon help. If a menu is being displayed, F1 will display help text describing that menu. -> s Open the Symbols menu, e and select Evaluate. The help window describes the type of expressions which can be entered for evaluation. To close the help windows. -> help Open the main help menu. Scroll down and select a help item by pressing Enter. You may also go directly to the help item by typing the command as an argument to help, i.e., 'help tm'. The on-line help screens are virtually identical to the command summary section of the user manual. Escape to return to the command line. -> r Open the Register menu. Press Enter. hyperSOURCE offers two types of windows: Data Windows are provided to monitor and/or modify data or debug variables. Examples are the Register window, the Memory window, the Breakpoints window, etc. These Data windows are 'sticky'; that is, they remain on screen when the key is pressed. They can be identified by the number assigned to them (i.e., 3:Register) and their contents can be edited. The Register window stays on screen. s The open Register window is automatically updated. 3 This shortcut can be used to select any open window, i.e., # will take you to the numbered window you select, in this case the Register window, #3. Close the Register window. -> s Transient Windows are provided as temporary g viewports to debug information. They pop up when selected, but close immediately with the key. They are not assigned numbers and cannot be edited. ============================================================================== VIEWING SOURCE FILES This section demonstrates the various ways you can use hyperSOURCE to view source files. -> inc setupr.inc list Use this include file to setup the emulator for the next portion of the tutorial. -> 1 Move the hyperSOURCE cursor into the Source window. The Source window is always #1, the Dialog window is always #2. The HOME environment variable determines whether the cursor will return to the Source window or to the command line by default. -> Use , , , and keys to scroll in the source window. Notice the current module name dm_main displayed on the barline at midscreen. g Alt-g is a shortcut key to Goto a new location. Pressing Enter accepts the offered default of current CS:IP, which is currently line #31 of main(). g Use delete to erase the default, then enter #43 #43 and Enter to go to line number 43. Now, using the cursor keys, position the cursor up ... one line, on line #42, under the p in printall. Press F2 to Follow, which switches the source window into the procedure printall(). The CS:IP of the emulator has not changed, only the source window view. Notice the module name on the barline is now $sub_func. This procedure works when: 1. The procedure to be followed is part of a module with a corresponding filename with .c extension. (Assuming EXT is set to .c in the .env file.) 2. The source file is in a subdirectory which is named in the SPATH variable. You can use the cursor keys to view sub_func.c. g Go (back) to CS:IP. Alt-g, main, would also work. The cursor should still be in the Source window; if not, use 1 to switch it there. Mixed mode shows both high-level statements and the (select Mixed) corresponding assembly-level instructions. Assembly source files can be shown; an example will (select Assembly) be shown in a few more steps. This display is disassembled machine code. Code On/Off controls the display of machine code in (select Code display) the source window when in assembly-level display. (select OFF) Turn off the code display in the source window. Resume high-level display. (select High Level) When the cursor is in the Source window, F8 is equivalent to the S command. F7 is equivalent to the S IN command. (But there is no subroutine to step into at this point, so it acts like the S command.) F6, 'go here' causes the emulator to begin execution at its current CS:IP, stopping on the line where the cursor is located. The Search key, F9, can be useful for finding a iteration specific location, symbol, etc. in the Source window. Return the cursor to the command line. -> reset Reset the emulator, positioning the CS:IP at the restart vector. -> s Single step the processor, jumping to the start of the assembly level initialization code. Even though the current module, $startup, is known by HS, the source file is not displayed because the source file extension is .ASM, not .C. To see the assembly source file, we will manually associate the current module with it. -> c Using the HS pull-down menus, we SET the current m module $startup to point to the source file startup startup.asm. As long as startup.asm is located in a subdirectory identified in SPATH, it will now be startup.asm displayed in the Source window. -> sou main The source command can be used from the command line to view any source file in SPATH. -> sou printall -> sou insert -> sou startup -> g Return source window to CS:IP Return the cursor to the command line. ============================================================================== EXAMINING & MODIFYING DATA This portion of the tutorial will demonstrate several ways in which you can view and modify data, in low to high level contructs. -> inc setupr.inc list Use this include file to reset the emulator to a known state, load the demo program and execute into main(). -> pause on Turn on the pause feature in the Dialog window. -> symb The Symbol command shows you all the symbols currently understood by HS. These were loaded from the OMF file. -> global To see only the Global symbols. -> local To see Local symbols in the current module. -> s Displays the modules currently loaded. m Displays symbols in a module. -> s Displays structure definitions. s -> b #43 Set a breakpoint, -> g then execute through the program one time to initialize variables. -> ?i Query the value of a variable. -> i=8 Assign i the value 8. -> i++ Auto-increment i. -> ?i Verify the new value. (Should be 9!) -> eva i Evaluate the current value of the variable i. -> eva i+4 Various C expressions can be evaluated. -> eva i*i -> char outbuf len Evaluate a C expression. sizeof (outbuf) -> local i is the only local variable in this module. -> mem 100 View a specific address in memory. Close the window. -> mem outbuf View the output buffer used by the procedure printall(). 2038 Enter the bytes shown into the memory assigned to outbuf. 2038 Change the memory display Size to byte. Return to the command line, leaving the memory window open. -> g Execute through the program loop one time. Notice that the memory window now contains different data (outbuf has been written to) and that it is automatically updated at the breakpoint. -> exa i Open a variable examine window to monitor the variable i, the program loop counter. d Select Decimal format, then press Esc to keep it on-screen. -> g Notice i is incremented on each program loop. -> 4 Switch to window #4 and close it. 3 Switch to window #3 and close it. -> go til #36 The procedure insert() is about to be executed. -> s in Step into insert(). -> d Open the Callstack window. Note that the c (current) scope of insert() is highlighted. View local symbols in the scope of insert(). Note that i=33. To close the Callstack:Locals window, a transient window. Select the scope of main(). To view local symbols in main(). Notice the variable i in this scope has a different value (this i is the main program loop counter). Close both windows. -> g hyperSOURCE is aware we've changed the program's scope. The go starts from the current CS:IP, after restoring the proper scope. Program breaks at the breakpoint set above on line #43 of main(). -> r Selects the register window, and leave it open. -> cx=5555 Change a register value from the command line. You can also do this directly in the Register window. Notice cx in the Register window is updated. -> 3 Close the Register window. ============================================================================== BREAKPOINTS This section will demonstrate how to access the various types of breakpoints in hyperSOURCE. -> inc setupr.inc list Use this include file to setup the emulator for the next section. -> b #33 Set a breakpoint on the statement on line #33. Notice the line number is highlighted, indicating the presence of a breakpoint. -> b By default, hyperSOURCE uses a software breakpoint. -> help b The help page on breakpoints will explain when and how hardware execution breakpoints are used. -> b exe #36 Force a hardware execution breakpoint on line #36. -> b -> trace View event and trigger settings in the MICE. Event 4 is used by hyperSOURCE to implement software breakpoints, so it should always be set as shown. ^G Use Control-G to "grow" the dialog window as necessary to see the output of the trace command. Events 5 and 6 are used to implement hardware breakpoints. If HS cannot set a software breakpoint because the address is in ROM, it will automatically use EV5 or EV6 and set a hardware breakpoint. -> go Load software breakpoints into emulator memory, and start emulation, breaking on the software breakpoint on line #33. Notice the MICE message indicates the break was due to EV4, which is the software breakpoint trap. -> view mix Software breakpoints are implemented by inserting INT3 instructions in the code. They are inserted only when you type go, and are removed after a breakpoint before the prompt is displayed. Thus, you will never see INT3's unless they are in your user code. If that happens, hyperSOURCE will report a spurious breakpoint, i.e., one it did not place. -> view hl Resume high-level display. -> pri ins The INT3 instructions are captured in the trace buffer, however, because they were executed! -> go This time the MICE message indicates the break was due to EV5, because of the hardware breakpoint we set on line #36. -> pri ins This time, the trace buffer contains no INT 3 instructions because we used an execution breakpoint. -> d Open the breakpoint window. HyperSOURCE supports b 32 software breakpoints, each of which can have a conditional statement and/or count. To insert a new breakpoint, #38 at line #38. To accept the definition. Highlight breakpoint 1: on line #36. Disable it. Highlight breakpoint 2: on line #38. Edit it. Move cursor to the CONDITION field. i>5 Type in the condition i>5. Accept it. Close the breakpoint window. -> i=2 Set i to 2 before running the test. -> g Start emulator. The program will run, stopping at line #38 each time it is encountered long enough to evaluate the condition. If not true, emulation resumes. When the condition evaluates true, emulation halts. -> ?i Query the value of i (should be 6). -> i=2 Reset the value of i to 2. These conditional breakpoints are powerful, but they require stopping the emulator long enough to evaluate the condition. Simple breaks can be defined and executed in realtime by using EV1 and EV2 of the MICE-III. -> tri ev1 or ev2 This command is extraneous UNLESS someone else left the MICE in TRIGGER CLEAR state. Just in case, type it in now, to tell the MICE to recognize either EV1 or EV2 as valid triggers. -> d Open the busEvent window to define Event 1. e Fill in the menu as shown here, to define Event 1 as the first write of 1234 to the memory address of i. = Bus Event ==================================== Event 1 Event 2 Event 3 CLear NO YES NO Address &i LOW Datum "1234" <-- Bus | Intr ACK off ----- "34" if 80C188 ! Fetch off Input off Output off Read off Write on Halt off Count press F10 to accept it. -> b 0 cle Clear all existing breakpoints. -> b 1 cle -> b 2 cle -> go Break is caused by EV1 (takes about 5 seconds). -> ?i Loop counter is equal to 1234 (or 34 if 80C188). -> pri Last (or next-to-last) cycle in the trace buffer is the write to 00B66, the address of i. Elapsed time is shown as approx. 5.6 seconds for the 80C186 and 1.9 seconds for the 80286. -> outbuf[6] A slightly more complex case: Knowing that our program alternates the writing of 34h and 35h to the 6th element of the array outbuf, program an event to cause a break when the value 34h is written to outbuf[6] for the 17th time. -> d Fill in the busEvent menu as shown: e = Bus Event ================================== Event 1 Event 2 Event 3 CLear NO YES NO Address &outbuf[6] LOW Datum 34h Bus Intr ACK OFF Fetch OFF Input OFF Output OFF Read OFF Write ON Halt OFF Count 17t Accept the definition. -> go Emulation halted by EV1. -> outbuf[6] Element 6 contains 4 (34h). -> pri And the last cycle in the trace buffer shows the write of 34h to the physical address of outbuf[6], which caused the break. -> phy &outbuf[6] Calculate the physical address of outbuf[6], which is 358. ============================================================================= TRACE ANALYSIS In this section you will use the MICE LAM board to capture and analyze data which was captured in the realtime trace buffer. -> inc setupr.inc list Re-load the demo program. -> go Free-run the program for a few seconds, then hit the ESCape key. -> halt Halt the emulator at a random location. The source window will update to show the location where you've stopped. The emulator and the trace buffer are both stopped and we will investigate various ways of viewing the data in the trace buffer. -> pause off Turn off screen pause. -> pri This is the simplest (default) way to display the trace buffer contents. The raw bus cycles captured in the trace buffer are displayed; the default is to just display the last 16 frames. ^G Press control-G several times to open the Dialog window. -> pri 700 Dump the trace buffer again, this time starting with frame #700. This will display the last FFh (256t) frames. -> pri 0 Dump the entire trace buffer (i.e., starting with frame #0). If you don't care to see the entire 2048 frames, press Escape. -> pri 0 354 359 The PRInt command can also "filter" the display, showing you only frames whose address falls within a certain range. In this case, it will show only those frames with address between 354h and 359h (physical addresses) inclusive. -> pri 0 B66 B66 You can also limit the display to frames with a single address, with this technique. You cannot use the PRInt command to filter the trace buffer display on data values, however. -> pri ins 6FF The PRInt command will also display the trace buffer contents as disassembled instructions; this command does so starting with frame #6FF in the buffer. -> pri sou 500 Display frames #500 to #7FF of the trace buffer in high-level language, using the original source files as reference. -> d r Open the RunTrace window. By default, only the last 100 frames are uploaded. This window now contains the same information just viewed in the dialog window with the PRInt command. Change the format of the code in this RunTrace window to high-level language. Change the number of frames to be uploaded from the MICE trace buffer. 250t For all future RunTrace window uploads in this debug session, bring up 250t frames. Re-upload with the new frame count (250t). Leave the RunTrace window on screen. -> go Restart emulation. -> halt Halt at a random location. Watch the RunTrace window be updated automatically. If the RunTrace window is on-screen, it (like all other windows) will be automatically updated at a breakpoint. -> qua "B66" Our demo program has a loop counter whose value is stored in memory at address B66 physical. Each time around the program loop, that address is read, incremented and written. This command will place a qualifier on the trace buffer such that ONLY accesses involving address B66 will be captured. -> go Start emulation; wait 5 seconds. -> halt Halt emulation at a random location. -> pri Notice that the ONLY bus cycles captured are involving accesses (R and W) to address B66. This is in contrast to the command above where we searched the trace buffer which contained ALL our program's bus cycles to find only those involving address B66. -> 3 Move back to the RunTrace window and select Cycle display format if necessary. (select Cycle) -> Close the RunTrace window. -> qua cle Clear the qualifier (i.e., accept all bus cycles into the trace buffer). Now we'll set up a trigger condition to stop the emulator at a specific point rather than randomly. -> eve 1 "B66" "x234" (If 80C186 or 80286) eve 1 "B66" "34" (If 80C188) Define Event 1, which we'll use as our triggger. Event 1 will be true if the address of i and any data value ending in "234" (or "34") appear on the bus simultaneously. (Don't-cares are allowed in event definitions if in double quotes.) -> tri ev1 Define the trigger as the occurence of EV1. -> go The program will run until EV1 is detected, then break, stopping both the emulator and the trace buffer. -> pri Verify that the (nearly) last frame in the trace buffer is the same as event 1. Usually the trace buffer will contain an extra frame or two because of "skidding" in the process of exiting emulation. ============================================================================= TRACING WITHOUT STOPPING THE EMULATOR The MICE emulator also has the ability to trigger the trace buffer WITHOUT stopping the emulator. This is accomplished by using the TRIgger RUN command, as shown below. -> inc setupr.inc list Reset the demo. -> trace View the current emulator Event, Trigger and Qualify settings. -> eve 1 &i 2345 (If 80C186 or 80286) eve 1 &i 45 (If 80C188) Define the event we will use to trigger the trace buffer, stopping the trace. -> tri run ev1 This command is the key to tracing without stopping emulation. It causes the MICE Events to become trace triggers, but NOT breakpoints. When the run parameter is specified with the trigger command, the emulator will continue to run when the event(s) are encountered, but the tracing process will halt. -> go nob Wait until you see the "Event 1 encountered" message. Note the R> prompt, indicating the emulator is still running. Note also that the green EP light is still lit on the emulator, indicating the emulator is running. R> mem 0B66 Try to view memory at address B66. As the message indicates, this cannot be done while the emulator is running. However, commands which do not involve emulator and/or target interaction CAN be entered, including new Event, Trigger and/or Qualify commands. If that is done, you MUST use the "GO NOBreak" command to re-start the trace buffer with the new definitions. R> halt Stop the emulator. -> up 1 Switch scope, up one level to main(). -> mem &i Note the (last) value stored in memory is greater than "2345" (or "45" for 80C188). w Select Word format for the memory window. Leave memory window open. -> pri Looking at the end of the trace buffer, however, shows that it stopped acquisition upon seeing Event 1. -> reset This completes the hyperSOURCE tutorial. -> quit Refer to the *.DOC files installed with hyperSOURCE for more information.