Volume 4 -- Issue 7 | April 1984

In This Issue...

- Cyclic Redundancy Check Subroutine
- More Clocks for Apple
- An Evening with Woz
- Converting to Intellec Hex Format
- Quick DOS Updating vs. MASTER CREATE
- Burning and Erasing EPROMS
- Using EXEC Files with Rak-Ware's DISASM
- Macro Source Code Now Available

Have we got news for you this month!

First, the simple announcements: We now have a new S-C Macro Cross Assembler for the Zilog Z-8 microprocessor. For only $32.50 Macro Assembler owners can add the ability to develop code for this popular chip.

And some good news for you Corvus hard disk owners: The problem in the Macro Assembler with having your Target File on a different volume from your source files is now whipped. Just send in your original Version 1.1 diskette for a free update.

Now the big story: After repeated requests from many users, we have decided to make available the complete Source Code for S-C Macro Assembler Version 1.1. See the last page of this issue for details.

Another product for which we have held back selling source code is the Double Precision Floating Point package for Applesoft (DPFP). From now on that product will be sold WITH source code, at the unforgiveably low price of $50. If you already are a registered owner of DPFP, or can supply other proof-of- purchase, we will send you the source code for $15. In case you never heard of DPFP, it is a 2048-byte &-module that provides 21-digit arithmetic and I/O for Applesoft.

Cyclic Redundancy Check Subroutine | Bob Sander-Cederlof

In the May 1983 AAL I wrote about checksums and parity, two ways to guarantee the integrity of data. In the world of microprocessors, you may encounter checksums at the end of data records on tape or disk, and parity bits on characters sent via a modem between computers. Tacking on parity bits and checksums to data helps in checking whether the data has been changed. However, there are more secure methods.

The best method I have ever heard of is commonly called Cyclic Redundancy Check, or CRC for short. Since it appears a lot more complicated than parity or checksum, it stands to reason it should have a more complex name. Right? But programmers have a way of reducing all complexity to three capital letters, so we will call it CRC.

First, a little review. The kind of parity I most frequently see adds an 8th bit on the left of a 7-bit value. The parity bit is chosen so that the total number of one-bits in the 8-bit byte is odd. For example, the seven bit number 1011010 (which might stand for an ASCII "Z") becomes 11011010, or $DA. If we run into the value 01011010 ($5A), we know there has been an error somewhere. Of course we don't know which bit is wrong, but we know at least one is because the total number of one-bits is even.

Checksums I run into are normally 8-bit or 16-bit "sums" of a large number of bytes or double bytes. I put "sums" in quotation marks because the checksum may be formed by the exclusive-or operation rather than true addition. In fact, it usually is. Eight-bit checksums formed with exclusive-or are in reality a kind of lengthwise parity. Each bit of the checksum is a parity bit for the column of bits in that position in the block of data.

In the old days, when dinosaurs first began to associate with herds of wildly spinning tape drives, you heard the words "vertical parity" and "longitudinal parity". Vertical parity was in those days a seventh bit for each six-bit character written on the tape, and longitudinal parity was a 7-bit character tacked on the end of each tape record, just like a checksum.

Enough review.

CRC is a much better scheme. A typical CRC implementation would add a 16-bit code to the end of a 256-byte block of data. A simple checksum would warn you of all single-bit errors, and some errors involving more than one bit. But CRC could detect all single and double bit errors, all errors with an odd number of error bits, all bursts of errors up to 16-bits in a row, and nearly all bursts of 17 or 18 bits in a row. Wow!

Also, you can even use CRC codes to CORRECT single-bit errors, if you trade off against some detection of longer error bursts.

You will run into CRC if you look into hard disks, or well- written modem software.

I like to write well-written programs, so I have been trying to understand CRC for some time now. A long time ago I had access to a book called "Error Correcting Codes", which is a classic. But I can't locate a copy now. I have seen numerous articles on the topic, especially in Computer Design. There was even one in Byte, Sept. 83, page 438. But I couldn't make the program in Byte work the way CRC's are supposed to, and I don't save my old Computer Design magazines.

Bobby Deen to the rescue. Bobby had a copy of a public domain routine by Paul Hansknecht, of Carpenter Associates, Box 451, Bloomfield Hills, MI 48013. Actually four little subroutines, to:

- clear the CRC code value
- cycle the eight bits of a data byte through the CRC algorithm
- finish the CRC calculation for an outbound message
- check the CRC bytes of a received message.

What is the basic idea of CRC? You perform an algorithm on each bit of a block of data, and get a CRC value. You append the CRC value to the data, and transmit both data and CRC. The receiver performs the same algorithm on the total record, both the data and the CRC code; when finished, the result of the receiver's CRC algorithm should be zero. If not zero, there was an error.

I am speaking in terms of sending and receiving, as in transmitting data with a modem. It all applies equally to writing and reading records on a disk, or even in adding check codes to a ROM. The programs I wrote and will list here merely operate on a buffer in RAM, so that I can see what is happening. You can extend them to practical uses from this base.

Which brings us to algorithms. The one Bobby gave me works like this:

The 16-bit value is initialized to zero. Then each bit in the data buffer is presented one at a time where the input arrow is. The bits in the 16-bit value are all shifted left one position, and the new data bit comes in the right end to become the new bit 0. The bit which shifts out the left end is Exclusive-ORed with the bits now found in bits 12, 5, and 0. That is, if the bit shifted out was a zero, nothing happens. If the bit shifted out was a one, exclusive or the 16 bit value with $1021.

If you understand the math of cyclic polynomials (I don't), this is supposed to be equivalent to X^16 + X^12 + X^5 + 1. An organization known to me only as CCITT recommends this polynomial. Another good one is reputed to be X^16 + X^15 +X^2 + 1, which is implemented by changing the exclusive or value from $1021 to $8005.

After all the bits of the data have been processed through the algorithm, 16 more zero bits are shifted through. After the zeroes, the value in the CRC register is the CRC code we append to the data.

The "receiver" processes the data the same way, starting by zeroing the CRC register. But instead of ending by shifting in 16 more zeroes, the receiver ends by shifting in the CRC code received.

I wanted to see if it really could find all those kinds of errors mentioned above. I wrote a program which would compute the CRC value and append it to a data block. Then I wrote another program which would "receive" the block and print out the resulting CRC value. Then I modified it to one-by-one toggle each bit position in the entire block, simulating a single bit error in each bit position in the whole buffer. My buffer is 256 bytes long, so that means 8*256 or 2048, different error positions. Actually 2064, because of the two bytes of CRC.

This way I experimentally "discovered" that the value produced by the CRC computation on the received message is dependent on the error bit position. It doesn't matter what the data was. Therefore, if I had a lookup table of 2064 16-bit entries, I could search through it and find out which bit position was wrong. There must be an easier way to figure out which bit position is wrong, but that is one of the things I still need to learn.

Okay. CRC.BYTE (lines 2890-3060) is a subroutine to process the eight bits of one byte through the CRC algorithm. CRC.BYTE needs to be called once for each byte of data in the buffer, plus either two zero bytes for a SEND routine or two CRC bytes for a RECV routine.

CRC.BUFFER (lines 2700-2850) is a little subroutine which calls CRC.BYTE once for each byte in the extended buffer. I assume it is called with PNTR pointing at the first byte in the buffer, and LIMIT is equated to the byte just beyond the end. The extended buffer includes either two zeroes on the end, or the two CRC bytes.

SETUP (lines 2610-2690) is a subroutine to initialize the CRC value register to zeroes, and to set PNTR to point at the beginning of the buffer.

The SEND and RECV routines at lines 1160-1380 simulate "sending" and "receiving" the buffer. Note that both SEND and RECV finish by displaying the calculated CRC value. SEND also stores the calculated CRC value into the end of the extended buffer. RECV should end up with a CRC value of $0000, unless there have been bits changed between calls to SEND and RECV.

TEST.SINGLE.BIT.ERRORS (lines 1390-1800) is the testing subroutine which I described above. It calls CRC.BUFFER 2064 times. Each time a different bit is changed. I print out the resulting CRC code each time, eight to a line, with the address of the byte containing the error bit leading the line. Before running TEST.SINGLE.BIT.ERRORS, you should run SEND to be sure a valid CRC code is installed in the extended test buffer.

I wrote another test routine which tests all two-bit errors. See TEST.DOUBLE.BIT.ERRORS, lines 1810-2410. The only trouble is it would take about 72 hours to run, so I haven't let it go all the way. I designed it to step through every bit position in two nested loops. If both loops happen to be at the same bit position, the bit will be toggled twice resulting in no error. I designed the program to print the address of the current byte whenever there was no error.

You might experiment with error bursts of various lengths, which should take no longer than TEST.SINGLE.BIT.ERRORS to run.

I would really be interested in finding out how to go backwards from a non-zero received CRC value to correct single-bit errors. Is there some easy way, without either a huge table or a long computation? If any of you know how, or have an article that tells how, pass it along.

      1000 *SAVE S.CRC GENERATOR (HANSKNECHT)
      1010 *--------------------------------
      1020 BUFFER .EQ $4000
      1030 LIMIT  .EQ $4102
      1040 *--------------------------------
      1050 CRC    .EQ $00,01
      1060 PNTR   .EQ $02,03
      1070 TPTR   .EQ $04,05
      1080 TMASK  .EQ $06
      1090 SPTR   .EQ $07,08
      1100 SMASK  .EQ $09
      1110 *--------------------------------
      1120 PRNTAX .EQ $F941
      1130 CROUT  .EQ $FD8E
      1140 PRBYTE .EQ $FDDA
      1150 COUT   .EQ $FDED
      1160 *--------------------------------
      1170 *      SIMULATE SENDING A BUFFER-FULL
      1180 *--------------------------------
      1190 SEND   JSR SETUP    CLEAR CRC, POINT AT BUFFER
      1200        LDA #0       CLEAR CRC BYTES IN BUFFER
      1210        STA LIMIT-1
      1220        STA LIMIT-2
      1230        JSR CRC.BUFFER    COMPUTE CRC OF 258 BYTES
      1240        LDX CRC      STORE CRC INTO LAST 2 BYTES
      1250        LDA CRC+1
      1260        STX LIMIT-1
      1270        STA LIMIT-2
      1280        JSR PRNTAX   DISPLAY THE CRC
      1290        JMP CROUT    <RETURN> AND RETURN
      1300 *--------------------------------
      1310 *      SIMULATE RECEIVING A BUFFER-FULL
      1320 *--------------------------------
      1330 RECV   JSR SETUP    CLEAR CRC, POINT AT BUFFER
      1340        JSR CRC.BUFFER    COMPUTE CRC OF 258 BYTES
      1350        LDX CRC      DISPLAY CRC IN HEX
      1360        LDA CRC+1
      1370        JSR PRNTAX
      1380        JMP CROUT
      1390 *--------------------------------
      1400 *      TRY "RECEIVING" THE 258 BYTES
      1410 *      WITH A KNOWN SINGLE-BIT ERROR.
      1420 *--------------------------------
      1430 TEST.SINGLE.BIT.ERRORS
      1440        LDA #BUFFER
      1450        STA TPTR     FOR TPTR = BUFFER TO LIMIT
      1460        LDA /BUFFER
      1470        STA TPTR+1
      1480 .1     LDA TPTR+1        PRINT TPTR"-"
      1490        LDX TPTR
      1500        JSR PRNTAX
      1510        LDA #"-"
      1520        JSR COUT
      1530        LDA #$80          FOR TMASK =
      1540        STA TMASK             $80,40,20,10,8,4,2,1
      1550 .2     LDY #0
      1560        LDA (TPTR),Y          INVERT BIT, MAKING ERROR
      1570        EOR TMASK
      1580        STA (TPTR),Y
      1590        JSR SETUP    CLEAR CRC, POINT AT BUFFER
      1600        JSR CRC.BUFFER        COMPUTE CRC
      1610        LDA #" "              PRINT " "CRC
      1620        JSR COUT
      1630        LDA CRC+1
      1640        LDX CRC
      1650        JSR PRNTAX
      1660        LDA (TPTR),Y          FIX ERRONEOUS BIT
      1670        EOR TMASK
      1680        STA (TPTR),Y
      1690        LSR TMASK         NEXT TMASK
      1700        BNE .2            ...MORE
      1710        JSR CROUT         PRINT<CR>
      1720        INC TPTR     NEXT TPTR
      1730        BNE .3
      1740        INC TPTR+1
      1750 .3     LDA TPTR
      1760        CMP #LIMIT
      1770        LDA TPTR+1
      1780        SBC /LIMIT+1
      1790        BCC .1       ...MORE
      1800        RTS
      1810 *--------------------------------
      1820 TEST.DOUBLE.BIT.ERRORS
      1830        LDA #BUFFER
      1840        STA SPTR     FOR SPTR=BUFFER TO LIMIT
      1850        LDA /BUFFER
      1860        STA SPTR+1
      1870 *--------------------------------
      1880 .1     LDA #$80     FOR SMASK=80,40,20,10,8,4,2,1
      1890        STA SMASK
      1900 *--------------------------------
      1910 .2     LDA #BUFFER  FOR TPTR=BUFFER TO LIMIT
      1920        STA TPTR
      1930        LDA /BUFFER
      1940        STA TPTR+1
      1950 *--------------------------------
      1960 .3     LDA #$80     FOR TMASK=80,40,20,10,8,4,2,1
      1970        STA TMASK
      1980 *--------------------------------
      1990 .4     LDY #0
      2000        LDA (TPTR),Y      MAKE FIRST ERROR
      2010        EOR TMASK
      2020        STA (TPTR),Y
      2030        LDA (SPTR),Y      MAKE SECOND ERROR
      2040        EOR SMASK
      2050        STA (SPTR),Y
      2060        JSR SETUP    CLEAR CRC, POINT AT BUFFER
      2070        JSR CRC.BUFFER    COMPUTE CRC
      2080        LDA (SPTR),Y      FIX BOTH ERRORS
      2090        EOR SMASK
      2100        STA (SPTR),Y
      2110        LDA (TPTR),Y
      2120        EOR TMASK
      2130        STA (TPTR),Y
      2140 *--------------------------------
      2150        LDA CRC      IF CRC=0, DISPLAY POINTERS
      2160        ORA CRC+1
      2170        BNE .5       ...CRC .NE. 0, SO CONTINUE
      2180        JSR DISPLAY.POINTERS
      2190 *--------------------------------
      2200 .5     LSR TMASK    NEXT TMASK
      2210        BNE .4       ...MORE
      2220        INC TPTR     NEXT TPTR
      2230        BNE .6
      2240        INC TPTR+1
      2250 .6     LDA TPTR
      2260        CMP #LIMIT
      2270        LDA TPTR+1
      2280        SBC /LIMIT+1
      2290        BCC .3       ...MORE
      2300 *--------------------------------
      2310        LSR SMASK    NEXT SMASK
      2320        BNE .2       ...MORE IN THIS BYTE
      2330        INC SPTR     NEXT SPTR
      2340        BNE .7
      2350        INC SPTR+1
      2360 .7     LDA SPTR
      2370        CMP #LIMIT
      2380        LDA SPTR+1
      2390        SBC /LIMIT+1
      2400        BCC .1       ...MORE
      2410        RTS
      2420 *--------------------------------
      2430 DISPLAY.POINTERS
      2440        LDA TPTR+1   PRINT TPTR"-"TMASK" ";
      2450        LDX TPTR
      2460        JSR PRNTAX
      2470        LDA #"-"
      2480        JSR COUT
      2490        LDA TMASK
      2500        JSR PRBYTE
      2510        LDA #" "
      2520        JSR COUT
      2530        LDA SPTR+1   PRINT SPTR"-"SMASK
      2540        LDX SPTR
      2550        JSR PRNTAX
      2560        LDA #"-"
      2570        JSR COUT
      2580        LDA SMASK
      2590        JSR PRBYTE
      2600        JMP CROUT
      2610 *--------------------------------
      2620 SETUP  LDA #0       CLEAR CRC
      2630        STA CRC
      2640        STA CRC+1
      2650        LDA #BUFFER  SET UP PNTR TO BUFFER
      2660        STA PNTR
      2670        LDA /BUFFER
      2680        STA PNTR+1
      2690        RTS
      2700 *--------------------------------
      2710 *      COMPUTE CRC FROM (PNTR) THRU LIMIT
      2720 *--------------------------------
      2730 CRC.BUFFER
      2740 .1     LDY #0       SCAN THRU THE BUFFER
      2750        LDA (PNTR),Y
      2760        JSR CRC.BYTE
      2770        INC PNTR     NEXT BYTE
      2780        BNE .2
      2790        INC PNTR+1
      2800 .2     LDA PNTR     CHECK LIMIT
      2810        CMP #LIMIT
      2820        LDA PNTR+1
      2830        SBC /LIMIT
      2840        BCC .1       MORE TO GO
      2850        RTS
      2860 *--------------------------------
      2870 *      COMPUTE CRC ON A SINGLE BYTE
      2880 *--------------------------------
      2890 CRC.BYTE
      2900        LDX #8       DO 8 BITS
      2910 .1     ASL          MSB OF BYTE TO CARRY
      2920        ROL CRC
      2930        ROL CRC+1
      2940        BCC .2       --> 0, GET NEXT BIT
      2950        PHA          --> 1, TOGGLE POLYNOMIAL BITS
      2960        LDA CRC
      2970        EOR #$21     TOGGLE BITS 0 AND 5
      2980        STA CRC
      2990        LDA CRC+1
      3000        EOR #$10     TOGGLE BIT 12
      3010        STA CRC+1
      3020        PLA
      3030 .2     DEX          NEXT BIT
      3040        BNE .1
      3050        RTS
      3060 *--------------------------------
      3070 *   FIND WHICH BIT IS BAD IN BUFFER+CRC
      3080 *
      3090 *      RESULT IS BIT POSITION IN MESSAGE,
      3100 *      WHERE THE FIRST BIT OF THE MESSAGE IS BIT 0
      3110 *      AND (IN THIS CASE) THE LAST CRC BIT IS BIT $80F.
      3120 *
      3130 *      ALGORITHM BY BRUCE LOVE, NEW ZEALAND
      3140 *--------------------------------
      3150 BIT.NUMBER .EQ $10,11
      3160 DUMMY.CRC  .EQ $12,13
      3170 *--------------------------------
      3180 FIND.BAD.BIT
      3190        LDA #$80F    TOTAL # BITS - 1
      3200        STA BIT.NUMBER    (WE WILL COUNT BACKWARDS)
      3210        LDA /$80F
      3220        STA BIT.NUMBER+1
      3230        LDA #$0001   STARTING POINT FOR BIT FINDER
      3240        STA DUMMY.CRC
      3250        LDA /$0001
      3260        STA DUMMY.CRC+1
      3270 .1     LDA CRC      COMPARE RECEIVED CRC WITH
      3280        CMP DUMMY.CRC        PROCESSED VALUE;
      3290        BNE .2       IF THEY MATCH, WE HAVE FOUND THE
      3300        LDA CRC+1    BAD BIT.
      3310        CMP DUMMY.CRC+1
      3320        BEQ .4       ...FOUND BAD BIT!
      3330 .2     LDA BIT.NUMBER        DECREMENT BIT COUNTER
      3340        BNE .3
      3350        DEC BIT.NUMBER+1
      3360        BMI .5       WENT TOO FAR
      3370 .3     DEC BIT.NUMBER
      3380        ASL DUMMY.CRC
      3390        ROL DUMMY.CRC+1
      3400        BCC .1
      3410        LDA DUMMY.CRC
      3420        EOR #$21
      3430        STA DUMMY.CRC
      3440        LDA DUMMY.CRC+1
      3450        EOR #$10
      3460        STA DUMMY.CRC+1
      3470        JMP .1
      3480 .4     LDA BIT.NUMBER+1  PRINT THE BIT NUMBER
      3490        JSR PRBYTE        (IF $8000, THE ERROR WAS
      3500        LDA BIT.NUMBER    NOT A SINGLE BIT)
      3510        JSR PRBYTE
      3520        JMP CROUT
      3530 .5     BRK
      3540 *--------------------------------

More Clocks for Apple | Bob Sander-Cederlof

Some more clock cards have been brought to my attention recently.

Prometheus Versacard includes a clock, and it is compatible with ProDOS due to its ability to emulate a Thunderclock. List price is $199.

Naturally, there is a clock on the Mountain Computer CPS/Multifunction Card. Naturally, because "CPS" stands for Clock Parallel Serial, the three functions the card supports. I cannot find a current price for this card.

Practical Peripherals is advertising ProClock, no price mentioned.

An Evening with Woz | Bill Morgan

Well, maybe not a whole evening, but a good portion of it. And certainly not alone, there were about 150 others in the room. But I did have the opportunity to attend a dinner sponsored by the River City Apple Corps, in Austin, Texas, and hear a speech by Steve Wozniak, the designer of our favorite pastime.

Most of Steve's speech was devoted to the history of his involvement with computers, and the development of the Apple II. That story is pretty well-known by now, so I won't mention too much of it here. The most interesting facets to me were hearing how much of a prankster Woz has always been, and finding out how many features of the Apple II were motivated only by Steve's desire to write a Breakout game in BASIC.

My favorite part of the evening was the question-and-answer session and the informal chats afterward, when we all got our chance to ask about what we really wanted to know. The first question is mine, the rest came from all around the room. These are the items that seem to be of most concern to AAL readers:

How about 65816 machines?

We're heavily involved in a computer based around that chip. But, final computer becoming a full-fledged product is subject to too many other variations, such as: you start working on it and you decide, no, this computer didn't come out right, it's too long, the actual date it will be done, it's not enough, we have to do a different product. So, it may be as soon as a few months, and it may be as long as a couple years before Apple has a product based around that new processor. Fortunately it is 100% compatible with what we've done before. Meaning it's a compatible upgrade, and that's what the Apple II has to do.

When can we expect a portable //e?

It's ... in the works. We're certainly thinking about it and delving into it and unless the project gets cancelled, probably very soon, but you can never say for sure until it's out.

How about color on the Macintosh?

There is no color on the Macintosh. ... Laser printers ... (and) ... LCD displays ... are converging on black and white technology being appropriate for that product line. There is no color for the Macintosh at this time.

Do you expect to see the 3 1/2 inch disks on the //e?

Apple believes that it's time to start moving the entire company toward higher density, better technology, more modern technology disk drives, and the 3 1/2 inch disk drives from Sony that is in the Lisa and Macintosh computers now is the proper direction to move in. It'll be interesting to see how it unfolds over time, as to how the conversion is made and yet extreme compatibility and support taken into account. All the software exists today on 5 1/4 inch disks. How do we get there?

It could be like your second disk can be a nice 3 1/2 inch with a lot more storage capability, but it may be years before it's proper to expect bootable software, to be able to boot on 3 1/2 inch drives. It's a challenge, and it just can't be turned over overnight. We could come out with a product for the Apple II today that uses a 3 1/2 inch drive as your only drive, and you know you can't run any of your software on it.... The sales of such a product would not start until there was a software base established.

What are you personally working on?

I'm interested in the future Apple II families. We're always pursuing higher performance-to-cost versions of the Apple II. And sometimes that's achieved by integrating several chips down into one custom chip, or by looking at accessories that are very commonplace, that almost everyone's going to buy for their //e. You can build one version of it with a lot of those accessories in and save a lot of money in the end, a lot of hassle. There are ways to improve the cost/performance ratio.

The other end, we're always trying to improve the capabilities of the machine. How are we going to eventually, someday, challenge IBM in the multi-megabyte computer world, the high-end? How are we going to improve performance?, increase screen resolution?, all those sort of questions, those sort of enhancements. I've been working very closely on one of those projects in Apple since returning.

... I think we've got to start heading towards a real, more useful home machine that does have a few of the things that we originally pursued, that we now believe is only about 10% of our market. Things such as: speech recognition and speech generation, built in, because they're relatively inexpensive and easy to do now to some level of quality. And it should also have more of the home-ish features, the features that are used in a personal, home environment built in.

So, that's the gist of it. I would like to thank Stuart Greenfield, of the River City Apple Corps, for the invitation to attend their dinner, and of course thank you, Woz, for coming to visit us.

One last note: Steve referred to a portable Apple //e as "probably very soon". Lately we've been hearing about the Apple //c, a 9-pound machine sporting 128K RAM, one disk drive, built-in serial and parallel ports, and no slots. Also no monitor, which sounds a little strange. Price -- $1200. The //c announcement is expected in late April.

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.

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.

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.

      1000 *SAVE S.INTELLEC HEX FORMATTER
      1010        .OR $300
      1020 *--------------------------------
      1030 PORT       .EQ $00,01
      1040 CHECK.SUM  .EQ $02
      1050 TYPE       .EQ $03
      1060 COUNT      .EQ $04
      1070 REMAINING  .EQ $05,06
      1080 *--------------------------------
      1090 A1     .EQ $3C,3D
      1100 A2     .EQ $3E,3F
      1110 A3     .EQ $40,41
      1120 A4     .EQ $42,43
      1130 A5     .EQ $44,45
      1140 *--------------------------------
      1150 CTRLY.VECTOR        .EQ $3F8 THRU $3FA
      1160 DOS.REHOOK          .EQ $3EA
      1170 *--------------------------------
      1180 MON.NXTA4           .EQ $FCB4
      1190 MON.CROUT           .EQ $FD8E
      1200 MON.PRHEX           .EQ $FDDA
      1210 MON.COUT            .EQ $FDED
      1220 MON.SETVID          .EQ $FE93
      1230 *--------------------------------
      1240 *      SETUP CONTROL-Y
      1250 *--------------------------------
      1260 SETUP  LDA #SEND.DATA
      1270        STA CTRLY.VECTOR+1
      1280        LDA /SEND.DATA
      1290        STA CTRLY.VECTOR+2
      1300        LDA #$4C
      1310        STA CTRLY.VECTOR
      1320        RTS
      1330 *--------------------------------
      1340 *   *0:XX YY   (LO,HI OF PORT)
      1350 *   *TARGET<START.END<Y>
      1360 *      IF PORT IS 0, DO NOT CHANGE OUTPUT
      1370 *      IF PORT IS 1...7, OUTPUT TO SLOT.
      1380 *         ELSE OUTPUT TO SUBROUTINE
      1390 *      SEND BYTES START...END
      1400 *
      1410 *      1.  TURN ON OUTPUT PORT
      1420 *      2.  SEND DATA RECORDS
      1430 *      3.  SEND EOF RECORD
      1440 *      4.  TURN OFF OUTPUT PORT
      1450 *--------------------------------
      1460 SEND.DATA
      1470        JSR TURN.ON.OUTPUT.PORT
      1480        JSR SEND.DATA.RECORDS
      1490        JSR SEND.EOF.RECORD
      1500        JMP TURN.OFF.OUTPUT.PORT
      1510 *--------------------------------
      1520 TURN.ON.OUTPUT.PORT
      1530        LDX PORT+1     HI-BYTE OF PORT SPECIFIED
      1540        BNE .1
      1550        LDA PORT       LO-BYTE, MUST BE SLOT
      1560        AND #$07
      1570        BEQ .3       SLOT 0, JUST SCREEN
      1580        ORA #$C0
      1590        BNE .2       ...ALWAYS
      1600 .1     TXA          HI-BYTE OF SUBROUTINE
      1610        LDX PORT       LO-BYTE OF SUBROUTINE
      1620 .2     STA $37
      1630        STX $36
      1640        JSR DOS.REHOOK
      1650 .3     RTS
      1660 *--------------------------------
      1670 SEND.DATA.RECORDS
      1680        LDA #0
      1690        STA TYPE
      1700        INC A2       POINT JUST BEYOND THE END
      1710        BNE .1
      1720        INC A2+1
      1730 .1     SEC
      1740        LDX #32
      1750        LDA A2       SEE HOW MANY BYTES LEFT
      1760        SBC A1
      1770        STA REMAINING
      1780        LDA A2+1
      1790        SBC A1+1
      1800        STA REMAINING+1
      1810        BNE .2       USE MIN(32,A2-A1+1)
      1820        CPX REMAINING
      1830        BCC .2
      1840        LDX REMAINING
      1850        BEQ .3       ...FINISHED
      1860 .2     STX COUNT
      1870        JSR SEND.RECORD
      1880        JMP .1       ...ALWAYS
      1890 .3     RTS
      1900 *--------------------------------
      1910 SEND.EOF.RECORD
      1920        LDY #0
      1930        STY COUNT
      1940        INY
      1950        STY TYPE
      1960        LDA A5       RUN ADDRESS (LO)
      1970        STA A4
      1980        LDA A5+1     RUN ADDRESS (HI)
      1990        STA A4+1
      2000        JMP SEND.RECORD
      2010 *--------------------------------
      2020 TURN.OFF.OUTPUT.PORT
      2030        JSR MON.SETVID
      2040        JMP DOS.REHOOK
      2050 *--------------------------------
      2060 SEND.RECORD
      2070        LDA #":"
      2080        JSR MON.COUT
      2090        LDA #0
      2100        STA CHECK.SUM
      2110        LDA COUNT
      2120        JSR SEND.BYTE
      2130        LDA A4+1
      2140        JSR SEND.BYTE
      2150        LDA A4
      2160        JSR SEND.BYTE
      2170        LDA TYPE
      2180        JSR SEND.BYTE
      2190        LDA COUNT
      2200        BEQ .2
      2210        LDY #0
      2220 .1     LDA (A1),Y
      2230        JSR SEND.BYTE
      2250        JSR MON.NXTA4
      2260        DEC COUNT
      2270        BNE .1
      2280 .2     SEC
      2285        LDA #0
      2290        SBC CHECK.SUM
      2300        JSR SEND.BYTE
      2310        JSR MON.CROUT
      2320        LDA #$8A     LINEFEED
      2330        JMP MON.COUT
      2340 *--------------------------------
      2350 SEND.BYTE
      2360        PHA
      2370        CLC
      2380        ADC CHECK.SUM
      2390        STA CHECK.SUM
      2400        PLA
      2410        JMP MON.PRHEX
      2420 *--------------------------------

Quick DOS Updating vs MASTER.CREATE | Bob Sander-Cederlof

When DOS was young, Apples tended to have varying amounts of memory under 48K. Some had 16K, which was the standard purchase at a computer store; others 24K, with one row of 16K and two of 4K; others 32K; and some 48K. Trying to write a DOS image that would fit all of these memories was quite a task.

Apple introduced the concept of a "master" and a "slave" disk. Master disks have a generic image of DOS. The boot process first loads the DOS image as though the machine only has 16K RAM, and then the image is relocated as high as possible in memory. Slave disks have a frozen image, already relocated for a particular memory size. The INIT command always creates a slave disk. In order to make a master disk you either copy and old master using COPYA (or equivalent copy program), or you use the MASTER.CREATE program on the DOS System Master Disk. (For a while the MASTER.CREATE program was called UPDATE 3.3.)

But now! But now you will have a difficult time finding an Apple with less than 48K memory. After all, the chips are only about a dollar apiece, or $8 to $12 for a set of eight. Who needs master disks anymore?

A lot of people think they do, because MASTER.CREATE is there and the reference manual makes such a big deal about it. And this causes a problem. What if I want a master disk with a modified DOS? MASTER.CREATE always reads the DOS image off the system master disk, and it is unmodified. Well, you can use a disk zap program on a copy of the system master.

Or, you can forget all about MASTER.CREATE and use my handy- dandy little patch installer. The program which follows reads the DOS image from the first 3 tracks into memory from $4000 thru $64FF. Then it installs patches from a table of patches; this part is almost identical to the patch installer published in the April 1983 issue of AAL. Finally it writes the patched DOS back on the first three tracks. And it does all this so fast you'll think it never happened.

Once you have coded the patches you want, and have tested them, you can update all your old DOS 3.3 disks almost as fast as you can open and close the drive door. With slight modifications, you could have it write the patched image on successive disks without re-reading and re-patching each time.

Looking at the program, Lines 1200-1240 do the overall job. Just below that, lines 1260-1290 give two entry points to a block of code that sets up an IOB for RWTS and then calls RWTS. The only difference between the two calls is the opcode, either READ or WRITE. Below that point, there is a backwards loop that counts from track 2, sector 4, back to track 0, sector 0. Just for fun, I print out the track and sector numbers just before reading or writing each sector. (If you get tired of the fun, simply delete line 1450, the JSR $F941.)

The DOS image on tracks 0, 1, and 2 is not in exactly the same order as you find it in memory after booting. Therefore the patcher maps patch addresses to the new locations. Lines 1060-1080 define the remapping constants. Addresses which in the running image will be between $B600 and $BFFF will be located from $4000 thru $49FF. If the original was a master, code which does the relocating part of the boot will be found from $4A00 thru $4BFF. The code between $9D00 and $B5FF will be found from $4C00 thru $64FF. The two constants DOS.9D and DOS.B6 are used in figuring the application points of the patches in lines 2110, 2350, and 2540.

For a full explanation of lines 1590-1900, see the April 1983 AAL, pages 24-27. The patch set up to be installed in lines 2020-2580 is the fast LOAD, BLOAD, RUN, BRUN patch from pages 2-8 of the same issue.

      1000 *SAVE S.APPLY DOS PATCHES
      1010 *--------------------------------
      1020 PNTR       .EQ $00,01
      1030 PATCH      .EQ $02,03
      1040 SECTOR.CNT .EQ $04
      1050 *--------------------------------
      1060 DOS.IMAGE  .EQ $4000 - $64FF
      1070 DOS.9D     .EQ $9D00-DOS.IMAGE-$0C00
      1080 DOS.B6     .EQ $B600-DOS.IMAGE
      1090 *--------------------------------
      1100 GETIOB     .EQ $3E3
      1110 RWTS       .EQ $3D9
      1120 *--------------------------------
      1130 IOB        .EQ $B7E8
      1140 IOB.VOLUME .EQ IOB+3
      1150 IOB.TRACK  .EQ IOB+4
      1160 IOB.SECTOR .EQ IOB+5
      1170 IOB.BUFADR .EQ IOB+8
      1180 IOB.OPCODE .EQ IOB+12
      1190 *--------------------------------
      1200 PATCH.DOS
      1210        JSR READ.DOS.IMAGE
      1220        JSR PATCHER
      1230        JSR WRITE.DOS.IMAGE
      1240        RTS
      1250 *--------------------------------
      1260 READ.DOS.IMAGE
      1270        LDA #$01     READ OPCODE
      1280        .HS 2C
      1290 WRITE.DOS.IMAGE
      1300        LDA #$02     WRITE OPCODE
      1310        STA IOB.OPCODE
      1320        LDA #0
      1330        STA IOB.BUFADR
      1340        STA IOB.VOLUME
      1350        LDA #DOS.IMAGE/256+16+16+5-1
      1360        STA IOB.BUFADR+1
      1370        LDA #2       TRACK 2
      1380        STA IOB.TRACK
      1390        LDA #4       SECTOR 4
      1400        STA IOB.SECTOR
      1410        LDA #16+16+5
      1420        STA SECTOR.CNT
      1430 .1     LDA IOB.TRACK
      1440        LDX IOB.SECTOR
      1450        JSR $F941
      1460        JSR GETIOB
      1470        JSR RWTS
      1480        LDY IOB.SECTOR
      1490        DEY
      1500        BPL .2
      1510        LDY #15
      1520        DEC IOB.TRACK
      1530 .2     STY IOB.SECTOR
      1540        DEC IOB.BUFADR+1
      1550        DEC SECTOR.CNT
      1560        BNE .1
      1570        RTS
      1580 *--------------------------------
      1590 PATCHER
      1600        LDA #PATCHES-1
      1610        STA PNTR
      1620        LDA /PATCHES-1
      1630        STA PNTR+1
      1640        LDY #0
      1650
      1660 .1     JSR GET.BYTE LENGTH OF NEXT PATCH
      1670        BEQ .4       FINISHED
      1680        TAX          SAVE LENGTH IN X
      1690        JSR GET.BYTE ADDRESS OF PATCH
      1700        STA PATCH
      1710        JSR GET.BYTE
      1720        STA PATCH+1
      1730
      1740 .2     JSR GET.BYTE
      1750        STA (PATCH),Y
      1760        INC PATCH
      1770        BNE .3
      1780        INC PATCH+1
      1790 .3     DEX
      1800        BNE .2
      1810        BEQ .1       ...ALWAYS
      1820
      1830 .4     RTS
      1840 *--------------------------------
      1850 GET.BYTE
      1860        INC PNTR
      1870        BNE .1
      1880        INC PNTR+1
      1890 .1     LDA (PNTR),Y
      1900        RTS
      1910 *--------------------------------
      1920 PATCHES
      1930 *--------------------------------
      1940 *  S.FAST LOAD
      1950 *
      1960 *      FAST "LOAD" AND "BLOAD"
      1970 *
      1980 *      INSTALLED IN UNUSED AREAS IN DOS 3.3:
      1990 *          $BA69-$BA95   (45 BYTES FREE)
      2000 *          $BCDF-$BCFF   (33 BYTES FREE)
      2010 *--------------------------------
      2020 READ.RANGE          .EQ $AC96
      2030 READ.NEXT.SECTOR    .EQ $B0B6
      2040 END.OF.DATA.ERROR   .EQ $B36F
      2050 RANGE.LENGTH        .EQ $B5C1,C2
      2060 RANGE.ADDRESS       .EQ $B5C3,C4
      2070 BUFFER.ADDRESS      .EQ $B5CB,CC
      2080 SECTOR.COUNT        .EQ $B5E4,E5
      2090 BYTE.OFFSET         .EQ $B5E6
      2100 *--------------------------------
      2110        .DA #P1.LENGTH,$BA69-DOS.B6
      2120        .PH $BA69
      2130 PATCH1 LDA BYTE.OFFSET       LAST BYTE OF
      2140        BNE GO.READ.RANGE     A SECTOR?
      2150        LDA RANGE.LENGTH+1    WHOLE SECTOR LEFT?
      2160        BEQ GO.READ.RANGE     NO.
      2170        LDA BUFFER.ADDRESS    SAVE BUFFER ADDRESS
      2180        PHA
      2190        LDA BUFFER.ADDRESS+1
      2200        PHA
      2210        LDA RANGE.ADDRESS     READ DIRECTLY
      2220        STA BUFFER.ADDRESS    INTO RANGE
      2230        LDA RANGE.ADDRESS+1
      2240        STA BUFFER.ADDRESS+1
      2250 READ.LOOP
      2260        JSR READ.NEXT.SECTOR
      2270        BCS .1
      2280        JMP PATCH2
      2290 .1     JMP END.OF.DATA.ERROR
      2300 GO.READ.RANGE
      2310        JMP READ.RANGE
      2320 P1.LENGTH .EQ *-PATCH1
      2330        .EP
      2340 *--------------------------------
      2350        .DA #P2.LENGTH,$BCDF-DOS.B6
      2360        .PH $BCDF
      2370 PATCH2 INC SECTOR.COUNT
      2380        BNE .1
      2390        INC SECTOR.COUNT+1
      2400 .1     INC RANGE.ADDRESS+1   NEXT PAGE
      2410        INC BUFFER.ADDRESS+1
      2420        DEC RANGE.LENGTH+1
      2430        BNE .2
      2440        PLA               RESTORE BUFFER
      2450        STA BUFFER.ADDRESS+1
      2460        PLA
      2470        STA BUFFER.ADDRESS
      2480        JMP READ.RANGE
      2490
      2500 .2     JMP READ.LOOP
      2510 P2.LENGTH .EQ *-PATCH2
      2520        .EP
      2530 *--------------------------------
      2540        .DA #P3.LENGTH,$ACA5-DOS.9D
      2550        .PH $ACA5
      2560 PATCH3 JMP PATCH1
      2570 P3.LENGTH .EQ *-PATCH3
      2580        .EP
      2590 *--------------------------------
      2600        .DA #0       END OF PATCHES

Burning and Erasing EPROMs | Bob Sander-Cederlof

We get a lot of questions about EPROM burners and erasers. Perhaps this list will help...

Burners:

PROM Blaster System, $119, Apparat, 4401 South Tamarac Parkway, Denver, CO 80237. Phone (303) 741-1778 or (800) 525-7674. Will burn most 24-pin EPROMS. Price includes personality modules for 2704, 2708, 2508, 2758, 2716(TI), 2516, 2716, 2532, 2732, 2732A, 68764, 2815, and 2816. ZIF socket for EPROM. No power switch, so you must power down the Apple whenever you insert or remove an EPROM.

Apple-PROM, $149.95, Computer Technology Associates, 1704 Moon N.E., Suite 14, Albuquerque, NM 87112. Phone (505)298-0942. Will burn most 24-pin EPROMS. DIP switch selection for 2708, 2716, 2516, 2532, 2732, 2732A, 2764, 2564. Low insertion force socket for EPROM.

Romwriter, $175, Mountain Computer....(I cannot find any recent ads, but they are still listed in distributor catalogs). We have heard that they are no longer manufacturing this card, but there are still many available. Only burns 2716 (single voltage version, not TI). ZIF for EPROM. Power switch on card allows you to safely insert and remove EPROMs without turning off your Apple. I have been using this one for several years with no problems, although I did rewrite the software to suit my own tastes and needs.

Quick EPROM Writer, $149, available from Handwell Corp., 4962 El Camino Real, Suite 119, Los Altos, CA 94022. Phone (415) 962-9265. Made in Taiwan by "COPAM". Burns both 24- and 28- pin EPROMs. All software is in firmware on the card. Nice menu select for 2716, 2516, 2532, 2732, 2732A, 2564, 2764, and 27128. No personality modules or switch selection required, as all configuration is software controlled. Power is applied to and removed from the ZIF socket under software control, so that EPROMs can be inserted and removed without turning off your Apple. Manual includes schematic, pinout diagrams for EPROMs, and a (sparsely) commented listing of firmware. The firmware apparently implements an intelligent burning algorithm, which burns twice as long as it takes to get the byte burned, rather than using a fixed delay for each byte. The result is much faster burn times than most other burners listed here.

HM3264, $395, Hollister Microsystems, 5081 Fairview, Hollister, CA 95023. Phone (408) 637-0753. Programs 2716, 2732, 2732A, 2764, and 27128. Henry Spragens uses this one, and says it is very well designed and built, though expensive. Henry has modified the software Hollister provides to use the intelligent burn algorithm (it was pretty slow until he did this). Hollister use the C800-CFFF address space, like Mountain Computer does, as a 2048-byte window into the EPROM. Bank switching on the card lets you program larger EPROMS. Power switch on card allows you to safely insert and remove chips. A program switch helps prevent inadvertent programming.

Model EP-2A-79, $169 plus $17 to $35 each for personality modules and $19 to $40 for software. Optimal Technology, Earlysville, VA 22936. Phone (804) 973-5482. Programs full range from 2708 through 27128, plus 38E70 and 8751 MPUs, assuming you purchase the corresponding personality modules and software. It is not clear to me whether this plugs directly into an Apple or requires a separate serial interface card.

Erasers:

QUV-T8 EPROM Erasers, Logical Devices, 1321E N.W. 65 Place, Fort Lauderdale, FL 33309. Phone (305) 974-0967 or (800) EE1-PROM (that is 331-7766). Four models, ranging from $49.95 to $124.95. I use and recommend the $97.50 model, which includes a slide-out tray, anti-static foam pad, UV indicator lens, timer, and safety interlock switch.

Spectronics, marketed by JDR Microdevices, 1224 S. Bascom Avenue, San Jose, CA 95128. Phone (800) 662-6279 or (408) 995-5430. Six models from $83 to $595. The $83 unit has no timer, all the others do. [ JDR's latest ad in Byte shows eight 250nsec 4116's for $7.95! ]

Jade Computer Products carries both brands of EPROM Erasers. Their price on the least expensive Spectronics is only $69.95.

Jameco Electronics lists an eraser for $79.95.

Using EXEC Files with Rak-Ware's DISASM | Bob Kovacs

[ Bob Kovacs is the author of DISASM, owner of Rak-Ware ]

I recently received a phone call from Alan Lloyd who had just purchased DISASM. He wanted to use it to disassemble the Autostart ROM so he could customize the code for a particular application. He was frustrated by the limited editing capabilities of DISASM which makes you start all over again if you don't catch your mistake before hitting RETURN. Since he had to enter the starting and ending addresses of over a dozen data tables, he began searching for an easier (and less painful) way of entering the data. He decided to try using an EXEC file with DISASM, and it worked! Well, sort of.

I thought about the problems he ran into, and found out some interesting things about the S-C Macro Assembler along the way. It turns out that with the help of a small patch to DISASM that it is possible to run the entire program via "remote control" using an EXEC file.

The first step is to create the TEXT file that will later be EXECed. You can do this in a word processor, if your word processor makes ordinary DOS text files. Or you can write an Applesoft program to help you build an array of addresses and the proper answers to the various prompts in DISASM, and then write a complete EXEC file. I decided to use the S-C Macro Assembler, because you can use the TEXT <filename> command to write a text file. You can have the assembler in the language card, DISASM at $800, the thing to be disassembled wherever you want, and pop back and forth fast as lightning.

Just enter each line of "source" as if you were responding to the questions put to you be DISASM. You can even include lines to turn on display of DOS commands and I/O (MONIOC), and the BLOADing of DISASM and NAMETABLE.

The S-C Macro Assembler does make one thing difficult. Some of the questions asked by DISASM require a null line (a RETURN all by itself), and S-C makes it very hard to get a null line. The first of these is used to terminate the entry of data table addresses. (Alan was satisfied to have his EXEC file stop here and take over manually.)

Normally, S-C does not let you enter totally empty lines. Typing a line number without any following text is one of the ways to DELETE a line, just as in both BASIC's. After a little experimenting I discovered a trick to fool the S-C input routine. I still don't get a totally empty line, but I can put extra RETURNs into an existing line. Here's how:

1. Type in the text of all the non-null lines you want in your EXEC file.
2. Use the EDIT command to insert extra RETURNs in the proper places: move the cursor to the character position desired, and type ctrl-O followed by RETURN to insert each extra RETURN. Each extra RETURN will show up as an inverse "M" as you are editing. Then type one more RETURN to exit the EDIT mode.

The next problem I ran into was the Y/N responses for the "Full Cross-Reference" and "Generate Text File" questions. DISASM looks directly at the keyboard for those two responses, so it is blind to any EXEC file inputs. A five byte patch fixes all that, so you can use EXEC file as well as keyboard inputs. Just change the code starting at location $C5A from AD 00 C0 10 FB to 20 18 FD 09 80.

The following arbitrary example illustrates how an EXEC file might look when typed into the S-C assembler (extra RETURNs are indicated by <M>):

         1000 MONIOC
         1010 BLOAD DISASM
         1020 BLOAD NAMETABLE
         1030 $800G          (Use call 2048 to EXEC from BASIC)
         1040 2              (select S-C Assembler format)
         1050 F800           (starting physical address)
         1060 F9B9           (ending physical address)
         1070 F800           (starting execution address)
         1080 F8CD           (table #1 start)
         1090 F8CF           (table #1 end)
         1100 3              (table #1 format)
         1110 F962           (table #2 start)
         1120 F9A5           (table #2 end)
         1130 5              (table #2 format)
         1140 F9A6           (table #3)
         1150 F9B3
         1160 8
         1170 F9B4           (table #4)
         1180 F9B9
         1190 6
         1200 <M>2000        (end of tables, and NAMETABLE address)
         1210 0              (no printer output)
         1220 <M>NYDEMO      (RETURN for no single cross reference,
                              N for no full cross reference,
                              Y for creating a textfile named DEMO)

(Of course, you realize that the explanatory comments in parentheses are not supposed to be typed.) I advise you to SAVE the lines on a file as S-C source code, using the SAVE <filename> command. This will become the copy you re-LOAD when you want to make changes. Then use the TEXT <filename> command to write out the EXEC file. Finally, EXEC <filename> to run the disassembly!

When EXECing, the table addresses are entered at a blinding speed that is almost imposssible to follow. If your text file has an error in it such that it does not conform to the DISASM input syntax, then things can go very wrong very fast. For those of you who would rather not see things move along quite so fast, I suggest adding a small patch to the COUT vector which provides a short delay. The following program works fine:

         $300:48       PHA
              A9 80    LDA #$80
              20 A8 FC JSR $FCA8
              68       PLA
              4C F0 FD JMP $FDF0

You can hook this into DOS from the assembler by typing "$36:00 03 N 3EAG". Then change line 1030 above to $812G (or CALL 2048+18 for EXEC from BASIC) to bypass DISASM's effort to setup the default DOS vectors.

Or you can even include all this stuff along with the original EXEC file. Either way, it is easier to use DISASM with an EXEC file when there are lots of data tables to be entered and you have fumble-fingers at the keyboard.

From now on, DISASM will be shipped with the five-byte patch indicated above already installed, and with two sample EXEC files designed to be EXECed from BASIC.

Macro Source Code Now Available | Bob Sander-Cederlof

We have finally become convinced that we should make the source code of our S-C Macro Assembler available for purchase. Many of you have requested, for a long time now. We have resisted, I suppose through a mild case of the same paranoia which causes so many other software publishers to use copy protection and license agreements (which we eschew).

We have absolutely no experiential basis for mistrust. You have all treated our previous offerings of source code in the most honorable fashion, and we expect you will continue to do so.

Effective immediately, registered owners of Version 1.1 of the S-C Macro Assembler can purchase the source code for $100. You will be able to assemble it to obtain a paper listing, study it to learn techniques, and modify it to your own tastes. We hope many of you will make improvements and send them back to us for inclusion in future versions.

The code resides on two nearly-full diskettes. You need at least two drives to assemble it. The source is fully commented, and is organized in a logical easy-to-follow manner.

If you do not yet own Version 1.1, you may purchase or upgrade to it simultaneously with the purchase of the source code, if you wish. If you are one of those who purchased the Version 4.0 source code, we will give you $40 credit toward the purchase of the Macro 1.1 source.

Another product for which we have held back selling source code is the Double Precision Floating Point package for Applesoft (DPFP). From now on that product will be sold WITH source code, at the unforgiveably low price of $50. If you already are a registered owner of DPFP, or can supply other proof-of-purchase, we will send you the source code for $15. In case you never heard of DPFP, it is a 2048-byte &-module that provides 21-digit arithmetic and I/O for Applesoft.

Apple Assembly Line is published monthly by S-C SOFTWARE CORPORATION, P.O. Box 280300, Dallas, Texas 75228. Phone (214) 324-2050. Subscription rate is $18 per year in the USA, sent Bulk Mail; add $3 for First Class postage in USA, Canada, and Mexico; add $12 postage for other countries. Back issues are available for $1.80 each (other countries add $1 per back issue for postage).

All material herein is copyrighted by S-C SOFTWARE, all rights reserved. Unless otherwise indicated, all material herein is authored by Bob Sander-Cederlof. (Apple is a registered trademark of Apple Computer, Inc.)