MOVING APPLICATION CODES TO ROM NOTES and AUTO START NOTES. Perhaps the most common question I get asked when answering the phone at New Micros is "How do I get my code into a ROM so that it will run?" The answer to this question varies greatly depending on the equipment that the user has available, and also on the needs of the program that is to be rommed. If the program has variables, then putting the variables in ROM is obviously going to create problems. Some users want to be able to power up their computers so that the dictionary is intact and the system is ready for new definitions. Others simply want their code to be executed automatically, and continuously--a typical request for an embedded application. In the pages that follow I will attempt to answer the most common variations of this problem. I will give examples from the simplest to the most complex. Really the question "How do I get my code into a ROM so that it will run?" should be broken down into two questions. "How do I get my code into a ROM?", and "How do I get my code to run out of a ROM?". The answer to the first question "How do I get my code into a ROM?", depends greatly on the tools that you have available. The simplest way to get your code into a ROM, is to start with a nonvolatile battery backed RAM module. You down load your code so that it is compiled into the BRAM (by pointing the DP to the location of this device.) After your code is downloaded and compiled by Forth, you remove the BRAM from the board, drop it in a EPROM programmer, and make a copy of it. So great! Now you've got your "code into a ROM." If you don't have a BRAM, it's going to be a little bit more time consuming and difficult. You start by downloading your code as before, into the SRAM of your system. Since you can't just pull the RAM out and drop it into the EPROM programmer, you've got to get the information back to your host computer some how. Probable the best way to do this is to use the Intel S record program that is provided in appendix AA. This program is designed to send to your host computer the Intel S record of your memory device. You need to be able to capture this information on your host computer. Most communication packages have a capture feature. When using MIRROR II the command is: CA ON Enable capture of your host, then give Forth the command: 0000 2000 INTEL-DUMP Forth proceeds to send to your host system the Intel S record of your code that you want to burn into your EPROM. (The command shown above is sending 8 k of bytes, starting at location 0 in RAM.) Now you've got an Intel S record file on your host computer that you can send to your EPROM programmer. Drop a EPROM in to your programmer and send the Intel S record. Now you've got your "code into a PROM." If your goal is to get your code into a EEPROM, this is even easier then into a EPROM. EEPROM's can be programmed directly on the New Micros processor board. To get your code into an EEPROM, install the EEPROM into one of the unused sockets on the board. Set the jumpers correctly for the device, and make a note of where in the memory map you have installed it. A good place to install it is location C000. Down load your code into the RAM as you have done before, then issue the command: FF6C 26 ! ( This is a patch needed on Max-Forth V3.3 and ( earlier. Make the patch before using any of ( the EE programming words. 0 C000 2000 EEMOVE This copies the 8K of RAM from 0 to 1FFF to the EEPROM located at C000. And now, once again you have your "code into a EEPROM." Well congratulations! Now lets get onto how to make it work/run/execute. Some thing that should be kept in mind is that Forth code is location dependent. This means that Forth code must be executed at the location where it is compiled. If code has been compiled and developed to run at location 200, copying this section of code to a ROM and installing it at address 2000 will not work. The code will not run at this address. Lets say you've got a real simple program. It doesn't have any variables and you just want it to go around and around in a loop. Such a program might look like this: : MAIN BEGIN ." Hello world. " CR AGAIN ; What you want is "MAIN" to be run (forever) when you do a power up, or a reset. Putting the code into ROM is only half the story, you've got to tell Forth that you want it to be executed. This is a pretty easy thing to do, because Forth has a built in auto-starting feature. You tell forth "Gee, when I hit a reset, or when I power up the system, I'd like you to execute my MAIN definition." You do this with the Forth AUTOSTART command. What you would issue is a command something like: 1000 AUTOSTART MAIN What this command does, is store a special autostart sequence (A55A) at location 1000. It then puts the CFA (code field address) of the word MAIN at location 1002. Now, if you hit a reset, Forth goes to its reset routine. One of the things that this reset routine does it look at every 1 K boundary for the A55A sequence. If it finds this A55A, it takes the next to location to be the CFA of the word to go and execute. So now we are getting somewhere. We know how to put our code into a ROM, and we know how to tell forth to execute the piece of code. Lets put it all together and see if we can really make it work. Here's a complete example: COLD HEX 100 TIB ! 50 TIB 2+ ! 200 DP ! : MAIN BEGIN ." Hello world. " CR AGAIN ; 1000 AUTOSTART MAIN These are the commands that you send to the Forth board. The assumptions being made are that you have RAM at 0 to 1FFF. The end result of sending the commands and definitions as shown above is RAM is now set up like you want your ROM to be. All you have to do is make a copy of this RAM and put it into a PROM. As discussed earlier, the way to put the code into the ROM will depend on the tools that you have available. Choose one of the methods most convenient for your system. The final thing to discuss here is what to do with the PROM that now has your code and AUTOSTART sequence instruction. Well, your going to have to install it in the socket that you were using for RAM. Pull out the SRAM, drop in the EPROM, and power up the system. You should see something like: Hello World. Hello World. Hello World. Hello World. ..... If you try putting this PROM at a location other than the address where the code was originally compiled it won't execute correctly. This is because Forth code is location sensitive. You do not need to be overly concerned about this during code development. It only means that it will be necessary to compile the code at the target address just prior to ROMMING it. During the compilation, obviosly RAM will need to be installed at this target address. This means that it will be necessary to temporarily install RAM in the location where you eventually plan to have your code in ROM. The method discussed so far will work with any Forth code as long as you don't use variables (We haven't discussed yet how to keep variables out of the ROM), and your happy to have the system run without ever making it to the outer Forth kernel for interactive development. The section of code shown could have done much more complex things. It could have, for instance checked the state of several port input lines, and based on the sate of these lines executed a different part of the code. The next subject that needs to be dealt with is the problem of variables. When you use the Forth VARIABLE command, Forth reserves space in the code section of memory for a variable. This is fine when your code is in RAM, but when you transfer it to ROM it's not going to work very well. The solution for this is rather easy. The user has to define a new Forth word, that will place the variables in a separate area where the user knows there will be free RAM. We'll define a new word in Forth and call it RAM-VARIABLE. It will work in the same manner as the original Forth VARIABLE command: 84 CONSTANT RAM-START VARIABLE NEXT-RAM-LOCATION 0 NEXT-RAM-LOCATION ! : RAM-VARIABLE NEXT-RAM-LOCATION @ DUP RAM-START + CONSTANT 2 + NEXT-RAM-LOCATION ! ; In this example, the start of free ram has been set to 84. 84 is internal to the 68HC11. Ram variables will be defined with the command: RAM-VARIABLE CLOCK-COUNT In this example, CLOCK-COUNT has been defined as a variable. If it is the first variable to be defined if will be at location 84. Setting RAM-START equal to 84 will have variables stored in the internal RAM to the 68HC11. Because of the limited space internal to the 68HC11, the user may also consider setting the RAM-START pointing to external RAM. Check the system documentation to see how the memory has been allocated internal to the 68HC11. External RAM may be available at location 180. The user will have to decide if there is enough space available internal to the 68HC11 or, if additional RAM will need to be provided. This depends greatly on the code and user needs. Many programmers are interested in having their systems start up with a pre-defined dictionary intact, and ready for new code development. Doing this requires a few more step than discussed above. Developing your code as normal. Decide on where to put your code. Assume for now that code will be stored at location C000. Define a word called BACK-UP : BACK-UP 6 DF96 6A CMOVE ; This words backs up all the Forth system variables from location 6 to location 71. The system variables are copied to memory from DF96 to location DFFF. Depending on your system, and where you are planning on placing RAM you may need to change the BACK-UP storage location value. Now define a word that will be used to link in your pre-defined dictionary, and set the system up in the user configured state: : SYSTEM-SETUP DF96 6 6A CMOVE ; Several things should be considered when thinking how you want the system to be configured on power up. It will be important to make sure that the DP is pointing to free RAM. The following is a complete example. The hardware system set up is discussed first. RAM at 0 to 1FFF ROM at C000 to DFFF The following can be entered manually, or be put in a file for download: COLD FORGET TASK HEX 100 TIB ! 50 TIB 2+ ! C004 DP ! ( Point DP to target ROM location. ) : FORGET-AFTER ( Redefining FORGET to work in the system. ) ' NFA 38 ! ; : BACK-UP ( Back will save the state of the system. ) 6 DF96 6A CMOVE ( Storing the variables to DF96...DFFF ) ; : INIT-A/D ( Sample program. ) 30 B030 C! ; : READ B031 C@ ; : VOLTAGE? INIT-A/D BEGIN READ . ?TERMINAL UNTIL ; : SYSTEM-SETUP ( Word used for restoring user system. ) DF96 6 6A CMOVE ; A44A C000 ! ( Temporary autostart pattern. ) ' SYSTEM-SETUP CFA C002 ! 200 DP ! ( Relocation DP to point to RAM. ) BACK-UP ( Issuing the system BACK-UP command. ) Now the code is stored at C000. If you have non-volatile RAM at C000 power can be turned off, other wise you will need to burn a PROM. When power is re-applied to the system, the system should start up, and if you type in WORDS you should see the dictionary entries that were entered earlier. The DP will be set to 200, and the TIB will be set to 100. Everything about the system will be in the same state as when the "SYSTEM-BACKUP" command was entered. Also, instead of doing a power down, the system can be tested by typing "COLD". This should cause the system to initialize, with your "SYSTEM-SETUP" section being executed. This should link in your previously defined words, and set the system up in the state that it was in when you issued the "SYSTEM-BACKUP" command. The Forth word "FORGET" needs to be re-defined as shown. This is because of the way in which the standard Forth FORGET word works. You don't want to forget words that are in your PROM. If you do FORGET words that are in your PROM, it will cause the system to jamb. This is because the DP will be left pointing into ROM. HEX VARIABLE CHKSUM : CE DUP A < IF 30 ELSE 37 THEN + EMIT ; ( CONVERT AND EMIT ) : 2.R FF AND 10 /MOD CE CE ; : 4.R 0 100 UM/MOD 2.R 2.R ; : INTEL-DUMP OVER + SWAP ( CONVERTS ADDRESS & COUNT TO UPPER, LOWER ADDRESS ) BEGIN CR 2DUP 20 + MIN ( MAKE NEXT LINE OF OUTPUT UP TO 32 BYTES LONG) SWAP ( BRING UP START ADDRESS, MOVE DOWN END ADDRESS ) ." :" ( BEGIN THE RECORD ) 2DUP - ( FIND OUT # OF BYTES IN THIS RECORD ) DUP CHKSUM ! ( BEGIN CHKSUM COMPUTATION ) 2.R ( PRINT # OF BYTES IN RECORD IN TWO DIGIT FIELD ) DUP >< FF AND OVER FF AND + CHKSUM +! ( ADD START ADDRESS TO CHKSUM ) DUP 4.R ( PRINT START ADDRESS IN FOUR DIGIT FIELD ) ." 00" ( PRINT RECORD TYPE, NO NEED TO ADD TO CHKSUM ) >R DUP R> ( MAKE START STOP #S FOR DO LOOP ) DO I C@ DUP 2.R ( PRINT HEX BYTE IN TWO DIGIT FIELD ) CHKSUM +! ( UPDATE CHKSUM ) LOOP CHKSUM 1+ C@ NEGATE 2.R ( PRINT CHKSUM NEGATED TWO DIGIT FIELD ) 1000 0 DO LOOP 2DUP = UNTIL ( KEEP GOING TILL LINE END IS = TO BLOCK END ) CR ." :00000001FF" CR ( TACK ON END RECORD ) 2DROP ;