!!! Please read 515MON21.DOC FIRST !!! Reprinted by permission of Intel Corporation, COPYRIGHT (C) 1979, 1980, 1981 INTEL CORPORATION AFTERMARKET USER'S MANUAL AND NOTES FOR THE MCS-51(tm) MONITOR VERSION X2.1 This is not an official Intel publication, but merely an attempt at documenting some ancient unsupported code from Intel Corp. Use it, but don't bother them for additional info - it doesn't exist anymore. All the mistakes herein are mine. Note that this is not a license to use in products the following document or any of the versions of the code it describes. For that, you need to talk to the Intel MCO Applications folks in Chandler AZ. PORTIONS COPYRIGHT (C) 1979, 1980, 1981 INTEL CORPORATION MCS-51 IS A REGISTERED TRADEMARK OF INTEL CORPORATION OTHER RESTRICTIONS MAY APPLY, YOUR MILEAGE MAY VARY Intel MCS-51 MONITOR Version X2.1 quick reference sheet -- SFR tokens, can be easily changed (no absolute address required) -- ACC token for the Accumulator B token for the B register DPTR token for the Data Pointer IE token for the Interrupt Enable register IP token for the Interrupt Priority register P1 token for Port 1 P3 token for Port 2 PC token for the Program Counter PSW token for the Program Status Word R0 token for general purpose Register 0 R1 token for general purpose Register 1 R2 token for general purpose Register 2 R3 token for general purpose Register 3 R4 token for general purpose Register 4 R5 token for general purpose Register 5 R6 token for general purpose Register 6 R7 token for general purpose Register 7 SCON token for the Serial Control Register SP token for the Stack Pointer TCON token for the Timer Control Register TMOD token for the Timer Mode Register -- commands to load, fill or display the various 8051 memory spaces -- CBYTE command to read code memory at Addr16 DBYTE command to read/write an internal data byte at Addr (0-7F) RBIT command to read/write an internal bit location (0-7F?) RBYTE command to read/write one of the registers (0-1F?) XBYTE command to read/write external data memory at Addr16 TO operand to specify end of a range -- commands to set/display breakpoints (MUST be on 2 or 3 byte instructions) -- BR command to display/set all breakpoints BR0 command to set the first breakpoint BR1 command to set the second breakpoint BR2 command to set the third breakpoint BR3 command to set the fourth breakpoint -- commands relating to single-step or go with/without breaks enabled -- GO command to execute user program MGO command to exit monitor and run user program STEP command to single-step the user program FROM modifies the PC before STEP or GO TILL PROG operand to enable program breakpoint(s) after GO DISPLAY simple trace of user program after STEP (must follow a comma) ALL DISPLAY operand - any type of instruction BR DISPLAY operand - display iff break is set SUBR DISPLAY operand - CALLs and RET(I)s XFER DISPLAY operand - CALLs, RETs and JMPs -- commands to upload/download Hex files from/to the current-loop console -- DOWNLOAD [comment] download hex data from the console to XDATA UPLOAD addr16 TO addr16 upload hex to the console from CODE MEMORY SEND send remainder of line to the console as message information Intel MCS-51 MONITOR Version X2.1 overview The Intel MCS-51 MONITOR Version X2.1 (the last known version) is a simple system allowing some limited debug of your programs. It allows you to load and save programs from RAM, single-step your code, or run at full system speed with breakpoints enabled. There's also a multi-step mode that displays some of the common registers after each line is executed. Also, when execution is halted, you can display or change any of the SFRs (many using symbolic names), and fill, change or display any of the memory spaces accessible to the 8051. The commands are in plain english, and can be abbreviated to just the first 2 letters if you don't want to type in the full word. There's also a secondary serial port (current-loop) using P3.4 and P3.5 that has a one-way pass-through mode you can use for serial monitoring. The primary interface is of course using P3.0 and P3.1 (RxD and TxD), and it will auto-baud lock to the first space you type as long as your speed is between 110 and 4800 baud. Most of the control is handled on-screen using the UART built into the 8051 (but not using the serial interrupt), with status and info showing up on the primary channel. Command syntax is absolute, and anything typed wrong will force an error. Command options will be shown in square brackets, anything else MUST be entered as shown. Info in parenthesis is for reference only, and shouldn't be entered. Numeric entry is in hexadecimal, and numbers starting with an alpha digit must be prefixed with a zero, as in 0A5 or 0DFF3. Only one leading zero is needed, but extras are ignored, as are trailing Hs (0FFH). The monitor automatically converts everything to upper-case alpha, so it'll be shown here that way. All spaces are optional, and are for your viewing convenience. The version of the monitor included in this archive isn't exactly the real one as in the chips, as the good folks at MCO Applications didn't keep the original around. This source was modified to produce a hex file to match the one taken from an old NMOS chip (version X2.1) I KNOW there are bound to be differences in the real source after comparison with the version I have. Caveat Emptor. I've successfully communicated with the monitor using several comm programs on the IBM, and other terminal emulator or modem software for other computers should work as well. If you want to use the hex upload/download facility, make sure you do it with an ASCII protocol, not one of the ones like XMODEM or such. Set comm parameters for 110-4800 baud, 8N1 (8 bits, no parity, 1 stop bit), full duplex (echo on). Don't forget, you're using direct connect signals and NOT the standard flow controls like RTS & CTS or XON & XOFF. Intel MCS-51 MONITOR Version X2.1 system limitations The features of the monitor require a few compromises in your code & hardware for the monitor to work properly. Since it's not a full featured real-time emulator, some tradeoffs are built-in to get the functions to perform, and you should be aware of them. First and foremost are limitations in hardware memory. The monitor MUST have a contiguous 256-byte block located on a page boundry (the least-significant byte = 00), and if you don't change the source code, the X2.1 version wants locations 2F00 through 2FFF. This page is sacred to the monitor, and your program CANNOT use, change, or reference anything in this area. Second, if you want to set breakpoints to halt execution of your program at a particular address, your program must be in RAM, not ROM, and the RAM your code executes from MUST be von Neumann, not Harvard or Aiken style architectures. This means the RAM can be accessed by either CODE or XDATA instructions, and either program lines or data bytes can reside within it. If your target system doesn't allow this, or you are using seperate CODE and XDATA that occupy the same addresses, you won't be able to set breakpoints but the rest of the monitor will function normally. Usually, adding a single AND gate (or two NAND gates) can solve this by ANDing /PSEN and /RD and using the resultant signal as the active-low output enable on your RAM chip(s). Von Neumann style memory is also required if you want to load a hex file into RAM, as you obviously can't load code memory into a PROM or ROM without programming it in. The monitor uses the Timer 1 interrupt to single-step, so you can't touch it if you want to single-step or multi-step. You could modify it to use one of the external interrupt pins, but it'll take some work. Timer 1 is also used for the serial baud-rate generation, and I think you can change it during the course of your program to whatever you want to use. The monitor reloads the serial channel SFRs every time it halts or steps, so it IS possible, but be careful. Just be aware that firing a Timer 1 interrupt will force a break. Oh, almost forgot - use a crystal around 8 to 12MHz for the autobaud routine to lock to your incoming space character. Slow speed crystals like 1.8432MHz won't lock at all. If you're using a slow crystal, you'll need to modify the serial interface routines to talk to your terminal properly. The next system limitation is what happens whenever you want to start or stop the monitor with STEPs or GOs. There's about 600 cycles worth of storing and restoring that happens to protect the state of the microprocessor as you go in and out of execution, and the micro will be doing reads and writes to RAM to save the current status. If you're using /RD or /WR to clock something, or your target system uses some of the Port 2 bits as I/O, your hardware may go nuts as you start and stop. There's no way around this but re-writing the entry and exit routines (not for the faint of heart), or using some other type of monitor. With some work, a monitor needs only enough room to save the areas it clobbers, and should fit in the top IDATA area of an 8052 to properly simulate an 8031. You could then use Timer 2 as the built-in serial port timer, and not frag the timer SFRs when both timers are in use in your target program. Finally, the monitor occasionally trashes XDATA locations 0000 and 0001. It seems to happen consistently whenever you hit a break after GO with breaks installed and enabled. I found it accidentally - was running the monitor code out of RAM, and it hung constantly. Use a ROM for the monitor code if you're going to modify it. Otherwise, remember the locations that get hit and watch out for erratic results in your target RAM allocations. Intel MCS-51 MONITOR Version X2.1 browsing in memory When execution is halted, you can display or change any of the hardware or memory spaces accessed by the 8051 using some simple commands in plain english. Most of the SFR mnemonics are supported by the monitor, so to see what happened to Port 1 for instance, you just type P1 and it'll show you the current state of the Port 1 pins. In the case here of a Port, the value on-screen is the level of the pins, NOT the last value written to the latch. Your hardware may alter the pin level beyond what was last written to the latch. To change the value, simple type P1 = value, where `value' is any valid hex number from 00 to 0FF. This works for ANY of the memory spaces or SFRs listed in the Quick Reference page, and the results happen immediately EXCEPT for changes to the program counter (PC). Changing the PC only has effect when you STEP or GO next. The full range of operations on various memory spaces is (XBYTE example): (load) XBYTE addr16 = data enters the value into XDATA at address addr16 (fill) XBYTE addr16 TO addr16 = data fills memory with a single byte value (display) XBYTE addr16 [TO addr16] does a hex dump to the screen These functions as shown above work on CBYTE (the code area), DBYTE (the chip's internal data memory), RBIT (the internal bit-addressable area), RBYTE (the internal registers), and XBYTE (the external data memory area). The TO options in square brackets allow you do the function over a range of addresses instead of just a single address location. Note that the standard monitor will NOT accept DBYTE, RBIT or RBYTE values above 7F, so the only way to modify the SFRs is with the tokenized names. I've seen a version modified for the 80152 that corrected this deficiency, so it's at least possible. You'll see an INVALID PARAMETER message if you attempt to do it access high internal RAM (as opposed to the SYNTAX ERROR you get elsewhere when your input line isn't understood). Intel MCS-51 MONITOR Version X2.1 single-stepping Once you have a program loaded, you can single-step or multi-step your code with the STEP command. Each time the monitor steps, it displays a line with handy information as shown below: *STEP PC=205B B=00 ACC=01 PSW=81 DPTR=2F91 P1=FF P3=FF RB0=5E F9 05 8D 00 00 5B 0E Note the zero after RB - it's showing you that Register Bank zero is the one currently selected by the two register select bits in the PSW. The full syntax allowed for the STEP command is as follows: STEP [FROM addr16] [,DISPLAY mode] The two optional commands allow you to change the PC before stepping and set the monitor into multi-step mode where it does multiple single-steps. If you use both optional commands, they must be entered in the order shown above. Don't forget the comma before the DISPLAY operand - it's required. Multi-step causes the monitor to start single-stepping your program, and shows the status line above after each step operation (if selected). Even when the status line isn't being shown, the monitor is stepping your program along about 200 times slower than normal. Displaying the status line slows it down even more because of the delay writing to the system console. DISPLAY modes allowed are as follows: ALL display status line after stepping any type of instruction BR display status line after break(s) if breakpoints are set SUBR display status line after stepping CALLs and RET(I)s XFER display status line after CALLs, RETs and JMPs The status line will show the conditions just after the instruction that forced the display, so the PC will reflect the changes from instructions that modify it like absolute or conditional branches. If your program modifies the select bits in the PSW, the register bank display will show the currently selected bank at the time of the status display. While you're in multi-step mode, the space bar will toggle execution on and off, giving you more time to see what happened. The escape key or return key will end multi-step mode and return you to the monitor prompt. Other keys will end multi-step and force a SYNTAX ERROR message. One nice thing - the multistep can be set to display the status line after ANY instruction, not just the 2 or 3 byte instructions you're forced to break on when GOing with breaks enabled. That's because it's stepping using the Timer 1 interrupt, not by over-writing your code with ACALLs like the GO does. Intel MCS-51 MONITOR Version X2.1 full-speed execution (GO) GO (and MGO) executes your program at full speed, unlike single or multiple step modes. There's a short delay before actual execution begins as the monitor restores the previous status of the microcontroller, but it's not likely you'll notice it unless you're using a REAL slow crystal. During GO, nothing will be shown on the screen as your program is executing other than the breaks (if you run with breaks enabled), and the only thing that'll stop it is a break or a hard RESET (watchdog RESETs will also stop it on the other 8051 derivatives). The full syntax for GO is: GO [FROM addr16] and/or [TILL PROG] or [FOREVER] to enable/disable breaks As with single-step, FROM will change the starting point of execution before GOing, else it'll start at the current value of the PC. The first GO should have a FROM unless you've already changed the PC, as the monitor doesn't know where your program is. The DOWNLOAD command doesn't change the PC when it loads a hex file, so the initial value of the PC is bound to be wrong. You have the option of enabling or disabling breaks by entering FOREVER to disable the current break settings, or entering TILL PROG to halt whenever the execution hits a valid break. Breaks MUST be on a 2 or 3 byte instruction to be properly executed as the monitor briefly replaces your code with an ACALL until the break is reached, and obviously can't replace a 1 byte instruction with a 2 byte ACALL. Invalid breaks will show up as ****, meaning it won't break at that setting. When a break is reached, the monitor will restore your original instruction and then single-step that instruction before halting, and the code inserted during execution will all disappear. The status line will display the results of your program up to and including the instruction at break, and then you'll get the monitor prompt (a star) to let you know it's your turn again. You can either enable or disable breaks, but not both at once. The serial channel is alive during execution, and everything BUT the escape key is passed to your program after a short delay. Calling 0193 will return the character in ACC, and calling 01B4 will set the carry if something's waiting in the buffer. At the same time, the current character will appear in the ACC. MGO is a special case of GO. The syntax is MGO addr16, and after restoring the state of the '51 it branches to your program and exits the monitor. The Timer 1 interrupt service is still there (it's in ROM), but none of the other monitor functions will be there until the next RESET. Break settings and the like will be ignored, and from that point on your program is in total control. Intel MCS-51 MONITOR Version X2.1 setting breaks Setting breaks is a dual-function operation, with different restrictions and results whether you're in multi-step mode or GOing with breaks enabled. In multi-step mode, breaks just display the status line for the BR display mode and can be set on any instruction. When GOing with breaks, the breakpoints will NOT be executed unless they're set on a 2 or 3 byte instruction. That's because the monitor replaces the instruction(s) with an ACALL or LJMP before GOing, and then restores your original instruction at break and single-steps the instruction before coming to a halt. Breaks set on a 1 byte instruction will be shown on screen as ****, indicating an invalid break address. Breaks not yet set will be shown as 0000. You can see the current breaks by typing BR . You can set or change individual breaks by entering the break number immediately after the BR, as in BR0 = 30FF or BR2 = 0C000, or you can change them all at once by just typing BR = addr16 [, addr16] [, addr16] [, addr16]. Don't forget the commas if you're setting multiple breaks. When you type BR = , it changes or sets the breaks starting with number 0, and optionally continues to break number 3. Intel MCS-51 MONITOR Version X2.1 hex uploads and downloads There's a nearly useless facility to send hex files to and from the monitor through the secondary serial channel, but the standard version will require a second computer to handle the transfer. I'd recommend changing it to use the system console (TxD & RxD) for the transfer to avoid another computer since all terminal emulation packages I've seen handle ASCII upload/downloads. The original reason for the secondary channel may be a Teletype reader/punch was cheaper storage (1980, don't forget), and talked to a dumb terminal. Also, the assorted development systems had a way to send/receive from the monitor. I'd recommend you modify the monitor ROM to run from the system console. While you're at it, you may want to completely hack out any of the code relating to the secondary serial channel (the software driven current-loop interface) unless you have a teletype or paper-tape reader floating around. The DOWNLOAD command has no operands at all. It merely loads a hex file from the secondary console to XDATA at the addresses contained in the hex records. If your RAM is set up as von Neumann, you can load your program that way, other- wise you're out of luck. There's a divisor that sets the secondary channel to 1/2 the baud rate of the primary one, so you'll have a hard time changing the baud rate and catching the program in time to get it across if you don't have two computers. The UPLOAD command is as follows: UPLOAD addr16 TO addr16. It takes the CODE area between the two addresses (start and end, not start and length) and converts it to Intel Hex records, then sends the records to the secondary serial channel. Again, if your RAM is von Neumann, it instead uses the program or data in the RAM as the source, not the code in ROM. After you type the the UPLOAD command line, the monitor will print `LOADING' and then halt. At this point, you can type anything you want and it will be sent to the secondary port. When you hit the at the end of your line, the upload will start. This is to allow you to get the receiver ready for the file, and you can just hit if you don't need to send any commands upstream. It's really just the SEND command tacked on to the beginning of the hex upload. The SEND command sends the remainder of the line to the secondary channel, up to and including the at the end. It was intended to allow communication with the Intellec emulator if memory serves me correctly. Maximum number of characters is equal to the normal max line length, or 80 total. Intel MCS-51 MONITOR Version X2.1 assorted other features When entering commands while execution is halted, the RUBOUT character will backspace and erase the last character you mis-typed (it's the DELETE key on IBM computers, the RUBOUT key on older computers). The BACKSPACE or left arrow keys will NOT generate a RUBOUT (ASCII 7F) on most computers, and will cause a SYNTAX ERROR to be displayed even if it looks right on your screen (if you have destructive backspace turned on in your terminal emulation software). Entering a control-X will abort the entire line just typed in in case you've really messed things up. Control-R will re-enter the line you've typed in so far, and I'm not sure why you'd want to do that. As expected, numbers are always entered and displayed in hexadecimal, and the leading character MUST be numeric (as in 0AA) when you're typing it in. It'll be shown without the leading zero most places. If the monitor expects a 16-bit address, it'll internally add the leading zeros if it needs to, and if you enter an H after the number (force of old habit), it's ignored. If you enter a number larger than the maximum allowed, say 1FF when you needed a byte value between 0 and 0FF, it'll squawk with an INVALID PARAMETER message and abort the command. One nice feature is the tokenizing used everywhere. Any of the commands or SFR names can be abbreviated as just the first 2 unique characters to save typing the whole thing in. I think there's a place or two it won't work right, but you'll have to find 'em on your own. Last but not least - the monitor just BEGS for additions and changes. The source isn't location sensitive as far as I can tell from the copy I built this version from. Also, if you want to add an expansion ROM, there's a set of jump tables at locations 26h through 46h for expansion use. I'd suggest adding a block move feature to the load\display section, and fixing the RBYTE routines so they work on all of the SFRs above 80h for 8052s and the like. Intel MCS-51 MONITOR Version X2.1 expansion ROM at 1000 The monitor is set to talk to an optional expansion ROM at location 1000h if one exists. To inform the monitor it's there, the first byte at 1000 must be 0A5, and the next byte at 1001 must be 02 (the first byte of an LJMP). If both of the above bytes are correct, the monitor will call the option ROM using an LCALL to the LJMP at location 1001 at a number of different places during its execution. I think it was intended for an assembler/disassembler, but never seen the code or heard of one. Some features you could add might be to dis- assemble the instruction at STEPs or breaks to make the whole session easier to understand, or a mini-assembler so you don't have to hand-calculate branch offsets and such as you're changing code. When the expansion ROM is checked and called, it's passed a function variable in R2. The variable tells the expansion ROM where the call originated from, although there's a host of other variables you can check to get a better idea. Here's the table of values and functions: 1 string test - it's checking your input line to see if it makes sense 2 token lookup - and here it's checking to see if it's a valid command code 3 special symbol - now it's looking for SFR names 4 step display - at this point, it's halted and about to print the status line 5 power on - got here just after reset (nothing set up, yet including UART) 6 start - waiting for your input line (prompt printed - waiting input) 7 keyword compare - similar to token lookup, but with strings (not tokens) Additionally, there's a jump table starting at 0026 that's reserved for the expansion ROM. The idea is to CALL the correct entry, and the called routine will do the function requested and end with a RET. Here's the jump table: 0026 output a character to the primary channel 0028 input a character from the primary channel 002A output a character to the secondary channel 002C input a character from the secondary channel 002E converts byte passed in R2 to hex-ascii and prints it 0030 converts word passed in R2 & R3 to hex and prints as a word 0032 scans an input stream looking for tokens 0034 print a CR LF pair to the primary serial channel 0036 write to one of the memory/register areas 0038 read from one of the memory/register areas 003A convert value passed in R2 to token label and print the token 003C print string - expects length as first byte of string @DPTR 003E scan input line until is reached 0040 print SYNTAX ERROR and warm-boot 0043 routine mentioned earlier - serial INPUT during GO from primary port 0045 also mentioned - carry set if a byte is the ACC for you The following patches are to remove all internal references to the secondary serial channel except for SEND. After adding these patches, the up/download functions will work from your terminal like they should. These patches only work on version X2.1 of the monitor, so don't use them if you've changed it. :10022000xxxxxxxxxxxxxx65xxxxxx65xxxxxxxx66 (these all divert the secondary :10023000xxxxxxxxxxxxxxxxxxxxxxxxxxxx65xx8C serial port calls to TxD & RxD, :100CF000xxxxxxxxxxxxxxxxxxxxxxxxxxxx6ExxA8 except for the one in SEND) :100D0000xxxxxxxxxxxxxxxxxxxx6Exxxxxxxxxx5C :100D1000xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx6EC8 :100D7000xxxxxxxxxxxx65xxxxxxxxxxxxxxxxxx41 :100DC000xxxxxxxxxxxxxxxxxxxxxxxxxx65xxxxDB :100DE000xxxxxxxxxxxxxxxx65xxxxxxxx65xxxx87 :100E0000xxxxxx000000xxxxxxxxxxxxxxxxxxxxD7 (NOPs the SEND after UPLOAD)