!pr1
Converting to Intellec Hex Format..........Bob Sander-Cederlof

The Prom Burners reviewed elsewhere in this issue all were designed especially for Apple owners, and plug directly into an Apple slot.  Believe it or not, there are other computers....  There are many brands of industrial grade prom burners which are not specifically designed for a particular computer host.  Most of these connect to a serial port on whatever host computer you choose.

Many of these expect to receive data in a special format, called by some the Intellec Hex Paper Tape Format.  Or, since at least two of those capitalized words are rather old- fashioned, the Intellec Hex Format.  Intellec is also used to communicate with a variety of Emulation hardware, and Development Systems.

The S-C Assemblers produce either binary files or the binary image in memory of the object code.  Can we convert a file or range of RAM to the Intellec format, and send it via a serial port?  Sure, it only takes a little software....

Let's first simplify a little by assuming we can BLOAD a binary file first into Apple RAM.  Then we only need a program which can translate and send a block of Apple RAM.

I would like to be able to operate the program by a control-Y monitor command.  I want to type what looks like the memory move ("M") command:  the first address specifies to the target system where the data should load; the second and third addresses specify the Apple RAM to be sent.  I also would like to be able to specify which slot the serial port is in, or where in RAM a subroutine to send bytes to the target system can be found if there is no intelligent interface card.

The program I wrote fulfills those wishes.  It loads at $300, and self-installs a control-Y vector for the monitor.  Location $0000 and $0001 must then be set to the low- and high-bytes of the port, and the "M"-like control-Y command can be typed.  For example:

      :BRUN B.INTELLEC
      :$0:2 0
      :$F800<800.FFF^O^Y

The port value is 0002, which means slot 2.  I wrote the program so that a port value 0001 thru 0007 means a slot number; 0100 thru FFFF means a subroutine address for your own driver; 0000 means send the output where it already is directed when you type the control-Y command.  The "^O^Y" on the third line above means "control-O control-Y", which is how you type a control-Y when you are in the S-C Assembler.  If you type the command from the monitor (*-prompt), omit the control-O.

I chose to send the data in a form that is compatible with both Intel and Zilog specifications, as I understand them.  I do not have any equipment which expects this format around here, so I cannot test the program with live data.  If you do, and you find I have mis-interpreted something, I would sure appreciate some feedback.

There are two types of records sent:  data and end-of-file records.  Each record begins with a colon (:) and ends with carriage return linefeed (CRLF, which is $8D8A).  The records consist of five fields.

!lm+5
Record length field:  two hex digits which specify how many bytes of data will be in the data field.  Will be 00 for an end-of-file record.  In keeping with Zilog's standard, the maximum length will be 32 bytes.

Address field:  four hex digits which specify the load address in a data record, and the run address in an end-of-file record.

Record type field:  00 for a data record, and 01 for an end-of-file record.

Data field:  two hex digits for each byte of data specified by the record length field.  Empty for an end-of-file record.

Checksum field:  two hex digits which represent the complement of the 8-bit sum of the 8-bit bytes which result from converting each pair of hex digits in the other four fields of this record to 8-bit binary values.
!lm-5

Lines 1250-1330 of the program set up the control-Y vector for the Apple Monitor.  If this is unfamiliar to you, you might like to read all about it in the October 1981 issue of Apple Assembly Line, pages 14-17.

Briefly, once set up, a control-Y command will branch to your own code.  It gives a way to extend the Apple monitor.  You can type up to three addresses before the control-Y, and they will be parsed by the monitor and saved in five two-byte variables (called A1, A2, A3, A4, and A5).  If you type "aaaa<bbbb.cccc" before the control-Y:

       aaaa will be saved in A4 and A5
       bbbb will be saved in A1 and A3
       cccc will be saved in A2

If you wish to pass more than three items of information to the control-Y routine, you can pre-store them in other locations.  In my routine, you must pre-store the port value in $0000 and $0001.

The whole control-Y routine is shown in just four lines of code:  lines 1470-1500.  Of course, these are all subroutine calls.

TURN.ON.OUTPUT.PORT (lines 1510-1650) examines locations $0000 and 0001.  If they contain 0000, then the output port is not changed.  If they contain 0001 thru 00FF, the lower three bits are used to select an intelligent interface card in slot 1 through 7.  A larger value indicates your own driver routine address.

TURN.OFF.OUTPUT.PORT (lines 2010-2030) sets the output back to the Apple screen.

SEND.DATA.RECORDS (lines 1660-1890) divides the area to be transmitted into a number of 32-byte blocks.  Each block is send as one data record.  The final block may be less than 32 bytes.

SEND.EOF.RECORD (lines 1900-2000) sends the end-of-file record.  The original loading address is assumed to be the run address.  If you would rather send 0000 for a run address, you can change lines 1960 and 1980 to "LDA #0".

SEND.RECORD (lines 2050-2330) formats and transmits one record of either type, using the count, address, and type information already setup by the caller.  It also updates A1 and A4 for the next record.

SEND.BYTE (lines 2340-2420) accumulates a byte in the checksum, and then converts it to two hex digits and transmits it.

You can use this program with any of the S-C Macro Assemblers or Cross Assemblers, exactly as shown.  If you are using some other brand of assembler, you will probably have to leave the assembler environment to load this program, load the object code you wish to transmit, and run the program.
