<

Volume 4 -- Issue 3 | December 1983

In This Issue...

- Listing of ProDOS $F90C-F995, $FD00-FE9A, $FEBE-FFFF
- More Assembly Listing into Text Files
- Note on Aztec C
- Generalized GOTO and GOSUB
- Timemaster II from Applied Engineering
- Finding Trouble in a Big RAM Card
- Converting S-C Source Files to Text Files
- Where To?, Revisited

Demise of Bailey's DataPhile Digest

Unfortunately, we no sooner sent out last month's AAL than we received a letter from the Baileys saying that they have ceased to publish the DataPhile Digest.

Quarterly Disk 13

QD 13 is now ready, and it includes both installments of ProDOS commented source code as listed last month and this. The code is in the format used by the S-C Macro Assembler. (Since the disk also includes the CONVERT S-C TO TEXT program in this issue, all of you can use it!) Quarterly Disks are $15 each, or $45 for a year's subscription.

Subscription Rates

Remember, subscriptions to Apple Assembly Line will be increasing to $18/year effective January 1. Since some of you may not receive this issue (or your renewal notice) until after that date, we'll extend the deadline to January 15 for renewals.

Commented Listing of ProDOS $F90C-F995, $FD00-FE9A, $FEBE-FFFF | Bob Sander-Cederlof

Last month I printed the commented listing of the disk reading subroutines. This month's selection covers disk writing, track positioning, and interrupt handling. Together the two articles cover all the code between $F800 and $FFFF.

Several callers have wondered if this is all there is to ProDOS. No! It is only a small piece. In my opinion, this is the place to start in understanding ProDOS's features: A faster way of getting information to and from standard floppies. But remember that ProDOS also supports the ProFILE hard disk, and a RAM disk in the extended Apple //e memory.

Further, ProDOS has a file structure exactly like Apple /// SOS, with a hierarchical directory and file sizes up to 16 megabytes.

Further, ProDOS includes support for a clock/calendar card, 80-columns with Smarterm or //e, and interrupts.

ProDOS uses or reserves all but 255 bytes of the 16384 bytes in the language card area (both $D000-DFFF banks and all #E000-FFFF). The 255 bytes not reserved are from $D001 through $D0FF in one of the $D000 banks. The byte at $D000 is reserved, because ProDOS uses it to distinguish which $D000 bank is switched on when an interrupt occurs. The space at $BF00-BFFF is used by ProDOS for system linkages and variables (called the System Global Page).

In addition, if you are using Applesoft, ProDOS uses memory from $9600-BEFF. This space does not include any file buffers. When you OPEN files, buffers are allocated as needed. CLOSEing automatically de-allocates buffers. Each buffer is 1024 bytes long. As you can see, with ProDOS in place your Applesoft program has less room than ever.

Track Seeking: $F90C-F995

The SEEK.TRACK subroutine begins at $F90C. The very first instruction multiplies the track number by two, converting ProDOS logical track number to a physical track number. If you want to access a "half-track" position, you could either store a NOP opcode at $F90C, or enter the subroutine at $F90D.

A table is maintained of the current track position for each of up to 12 drives. I call it the OLD.TRACK.TABLE. The subroutine GET.SSSD.IN.X forms an index into OLD.TRACK.TABLE from slot# * 2 + drive#. There are no entries in the table for drives in slots 0 or 1, which is fine with me. ProDOS uses these slots as pseudo slots for the RAM-based pseudo-disk and for ProFILE, if I remember correctly.

The code in SEEK.TRACK.ABSOLUTE is similar but not identical to code in DOS 3.3. The differences do not seem to be significant.

Disk Writing: $FD00-FE9A

The overall process of writing a sector is handled by code in RWTS, which was listed last month. After the desired track is found, RWTS calls PRE.NYBBLE to build a block of 86 bytes containing the low-order two bits from each byte in the caller's buffer. PRE.NYBBLE also stores a number of buffer addresses and slot*16 values inside the WRITE.SECTOR subroutine. Next RWTS calls READ.ADDRESS to find the sector, and then WRITE.SECTOR to put the data out.

WRITE.SECTOR is the real workhorse. And it is very critically timed. Once the write head in your drive is enabled, every machine cycle is closely counted until the last byte is written. First, five sync bytes are written (ten bits each, 1111111100). These are written by putting $FF in the write register at 40 cycle intervals. Following the sync bytes W.S writes a data header of D5 AA AD.

Second, the 86-byte block which PRE.NYBBLE built is written, followed by the coded form of the rest of your buffer. WRITE.SECTOR picks up bytes directly from your buffer, keeps a running checksum, encodes the high-order six bits into an 8-bit value, and writes it on the disk...one byte every 32 cycles, exactly. Since your buffer can be any arbitrary place in memory, and since the 6502 adds cycles for indexed instructions that cross page boundaries, WRITE.SECTOR splits the buffer in parts before and after a page boundary. All the overhead for the split is handled in PRE.NYBBLE, before the timed operations begin.

Finally, the checksum and a data trailer of DE AA EB FF are written.

Empty Space: $FEBE-FF9A

This space had no code in it. Nearly a whole page here.

Interrupt & RESET Handling: $FF9B-FFFF

If the RAM card is switched on when an interrupt or RESET occurs, the vectors at $FFFA-FFFF will be those ProDOS installed rather than the ones permanently coded in ROM. It turns out the non-maskable interrupt (NMI) is still vectored down into page 3. But the more interesting IRQ interrupt is now vectored to code at $FF9B inside ProDOS.

The ProDOS IRQ handler performs two functions beyond those built-in to the monitor ROM. First, the contents of location $45 are saved so that the monitor can safely clobber it. Second, a flag is set indicating which $D000 bank is currently switched on, so that it can be restored after the interrupt handler is finished. (The second step is omitted if the interrupt was caused by a BRK opcode.)

If the IRQ was not due to a BRK opcode, a fake "RTI" vector is pushed on the stack. This consists of a return address of $BF50 and a status of $04. The status keeps IRQ interrupts disabled, and $BF50 is a short routine which turns the ProDOS memory back on and jumps up to INT.SPLICE at $FFD8:

           BF50-  8D 8B C0  STA $C08B
           BF53-  4C D8 FF  JMP $FFD8

Of course, before coming back via the RTI, ProDOS tries to USE the interrupt. If you have set up one or more interrupt vectors with the ProDOS system call, they will be called.

INT.SPLICE restores the contents of $45 and switches the main $D000 bank on. Then it jumps back to $BFD3 with the information about which $D000 bank really should be on. $BFD3 turns on the other bank if necessary, and returns to the point at which the interrupt occured.

The instruction at $FFC8 is interesting. STA $C082 turns on the monitor ROM, so the next instruction to be executed is at $FFCB in ROM. This is an RTS opcode, so the address on the stack at that point is used. There are two possible values: $FA41 if an IRQ interrupt is being processed, or $FA61 if a RESET is being processed. This means the RTS will effectively branch to $FA42 or $FA62.

Uh Oh! At this point you had better hope that you are not running with the original Apple monitor ROM. The Apple II Plus ROM (called Autostart Monitor) and the Apple //e ROM are fine. $FA42 is the second instruction of the IRQ code, and $FA62 is the standard RESET handler. But the original ROM, like I have in my serial 219 machine, has entirely different code there.

I have an $FF at $FA42, followed by code for the monitor S (single step) command. And $FA62 is right in the middle of the S command. There is no telling what might happen, short of actually trying it out. No thanks. Just remember that RESET, BRK, and IRQ interrupts will not work correctly if they happen when the RAM area is switched on and you have the old original monitor in ROM.

There is another small empty space from $FFE9 through $FFF9, 17 bytes.

Perhaps I should point out that the listings this month and last are from the latest release of ProDOS, which may not be the final released version. However, I would expect any differences in the regions I have covered so far to be slight.

[ In this web edition I have included the entire code, instead of just the pieces not printed in the November 1983 issue.]

      1000        .TI 76,PRODOS F800-FFFF.....COMMENTED BY RBS-C  11-8-83............
      1010 *SAVE S.PRODOS F800-FFFF
      1020 *--------------------------------
      1030 RUNNING.SUM        .EQ $3A
      1040 TBUF.0             .EQ $3A
      1050 BYTE.AT.BUF00      .EQ $3B
      1060 BYTE.AT.BUF01      .EQ $3C
      1070 LAST.BYTE          .EQ $3D
      1080 SLOT.X16           .EQ $3E
      1090 INDEX.OF.LAST.BYTE .EQ $3F
      1100 *--------------------------------
      1110 RWB.COMMAND .EQ $42
      1120 RWB.SLOT    .EQ $43   DSSSXXXX
      1130 RWB.BUFFER  .EQ $44,45
      1140 RWB.BLOCK   .EQ $46,47   0...279
      1150 *--------------------------------
      1160 BUFF.BASE .EQ $4700 DUMMY ADDRESS FOR ASSEMBLY ONLY
      1170 *--------------------------------
      1180 SAVE.LOC45 .EQ $BF56
      1190 SAVE.D000  .EQ $BF57
      1200 INTAREG    .EQ $BF88
      1210 INTBANKID  .EQ $BF8D
      1220 IRQXIT.3   .EQ $BFD3
      1230 *--------------------------------
      1240 DRV.PHASE  .EQ $C080
      1250 DRV.MTROFF .EQ $C088
      1260 DRV.MTRON  .EQ $C089
      1270 DRV.ENBL.0 .EQ $C08A
      1280 DRV.Q6L    .EQ $C08C
      1290 DRV.Q6H    .EQ $C08D
      1300 DRV.Q7L    .EQ $C08E
      1310 DRV.Q7H    .EQ $C08F
      1320 *--------------------------------
      1330 *                 <<<COMPUTED >>>
      1340 MODIFIER .EQ $60  <<<SLOT * 16>>>
      1350 *--------------------------------
      1360        .OR $F800
      1370        .TA $800
      1380 *--------------------------------
      1390 *      READ/WRITE A BLOCK
      1400 *
      1410 *      1.  ASSURE VALID BLOCK NUMBER (0...279)
      1420 *      2.  CONVERT BLOCK NUMBER TO TRACK/SECTOR
      1430 *          TRACK = INT(BLOCK/8)
      1440 *          BLOCK   SECTORS
      1450 *          -----  ---------
      1460 *            0     0 AND 2
      1470 *            1     4 AND 6
      1480 *            2     8 AND 10
      1490 *            3    12 AND 14
      1500 *            4     1 AND 3
      1510 *            5     5 AND 7
      1520 *            6     9 AND 11
      1530 *            7    13 AND 15
      1540 *      3.  CALL RWTS TWICE
      1550 *      4.  RETURN WITH ERROR STATUS
      1560 *--------------------------------
      1570 RWB
      1580        LDA RWB.BLOCK     BLOCK MUST BE 0...279
      1590        LDX RWB.BLOCK+1
      1600        STX RWTS.TRACK
      1610        BEQ .1       ...BLOCK # LESS THAN 256
      1620        DEX
      1630        BNE .5       ...BLOCK # MORE THAN 511
      1640        CMP #$18
      1650        BCS .5       ...BLOCK # MORE THAN 279
      1660 .1     LDY #5       SHIFT 5 BITS OF TRACK #
      1670 .2     ASL              RWTS.TRACK   A-REG
      1680        ROL RWTS.TRACK   ----------   --------
      1690        DEY               00TTTTTT    ABC00000
      1700        BNE .2
      1710        ASL          TRANSFORM BLOCK # INTO SECTOR #
      1720        BCC .3       ABC00000 --> 0000BC0A
      1730        ORA #$10
      1740 .3     LSR
      1750        LSR
      1760        LSR
      1770        LSR
      1780        PHA
      1790        JSR RWTS     R/W FIRST SECTOR OF BLOCK
      1800        PLA
      1810        BCS .4       ...ERROR
      1820        INC RWB.BUFFER+1
      1830        ADC #2
      1840        JSR RWTS     R/W SECOND SECTOR OF BLOCK
      1850        DEC RWB.BUFFER+1
      1860 .4     LDA RWTS.ERROR
      1870        RTS
      1880 *---BLOCK NUMBER > 279-----------
      1890 .5     LDA #$27     I/O ERROR
      1900        SEC
      1910        RTS
      1920 *--------------------------------
      1930 *      READ/WRITE A GIVEN SECTOR
      1940 *--------------------------------
      1950 RWTS
      1960        LDY #1       TRY SEEKING TWICE
      1970        STY SEEK.COUNT
      1980        STA RWTS.SECTOR
      1990        LDA RWB.SLOT
      2000        AND #$70     0SSS0000
      2010        STA SLOT.X16
      2020        JSR WAIT.FOR.OLD.MOTOR.TO.STOP
      2030        JSR CHECK.IF.MOTOR.RUNNING
      2040        PHP          SAVE ANSWER (.NE. IF RUNNING)
      2050        LDA #$E8     MOTOR STARTING TIME
      2060        STA MOTOR.TIME+1  ONLY HI-BYTE NECESSARY
      2070        LDA RWB.SLOT      SAME SLOT AND DRIVE?
      2080        CMP OLD.SLOT
      2090        STA OLD.SLOT
      2100        PHP               SAVE ANSWER
      2110        ASL               DRIVE # TO C-BIT
      2120        LDA DRV.MTRON,X   START MOTOR
      2130        BCC .1            ...DRIVE 0
      2140        INX               ...DRIVE 1
      2150 .1     LDA DRV.ENBL.0,X  ENABLE DRIVE X
      2160        PLP               SAME SLOT/DRIVE?
      2170        BEQ .3            ...YES
      2180        PLP          DISCARD ANSWER ABOUT MOTOR GOING
      2190        LDY #7       DELAY 150-175 MILLISECS
      2200 .2     JSR DELAY.100     DELAY 25 MILLISECS
      2210        DEY
      2220        BNE .2
      2230        PHP          SAY MOTOR NOT ALREADY GOING
      2240 .3     LDA RWB.COMMAND   0=TEST, 1=READ, 2=WRITE
      2250        BEQ .4            ...0, MERELY TEST
      2260        LDA RWTS.TRACK
      2270        JSR SEEK.TRACK
      2280 .4     PLP          WAS MOTOR ALREADY GOING?
      2290        BNE .6       ...YES
      2300 .5     LDA #1       DELAY 100 USECS
      2310        JSR DELAY.100
      2320        LDA MOTOR.TIME+1
      2330        BMI .5       ...WAIT TILL IT OUGHT TO BE
      2340        JSR CHECK.IF.MOTOR.RUNNING
      2350        BEQ .14      ...NOT RUNNING YET, ERROR
      2360 .6     LDA RWB.COMMAND
      2370        BEQ .17      CHECK IF WRITE PROTECTED
      2380        LSR          .CS. IF READ, .CC. IF WRITE
      2390        BCS .7       ...READ
      2400        JSR PRE.NYBBLE   ...WRITE
      2410 .7     LDY #64      TRY 64 TIMES TO FIND THE SECTOR
      2420        STY SEARCH.COUNT
      2430 .8     LDX SLOT.X16
      2440        JSR READ.ADDRESS
      2450        BCC .10      ...FOUND IT
      2460 .9     DEC SEARCH.COUNT
      2470        BPL .8       ...KEEP LOOKING
      2480        LDA #$27     I/O ERROR CODE
      2490        DEC SEEK.COUNT   ANY TRIES LEFT?
      2500        BNE .14      ...NO, I/O ERROR
      2510        LDA CURRENT.TRACK
      2520        PHA
      2530        ASL          SLIGHT RE-CALIBRATION
      2540        ADC #$10
      2550        LDY #64      ANOTHER 64 TRIES
      2560        STY SEARCH.COUNT
      2570        BNE .11      ...ALWAYS
      2580 .10    LDY HDR.TRACK     ACTUAL TRACK FOUND
      2590        CPY CURRENT.TRACK
      2600        BEQ .12           FOUND THE RIGHT ONE
      2610        LDA CURRENT.TRACK WRONG ONE, TRY AGAIN
      2620        PHA
      2630        TYA          STARTING FROM TRACK FOUND
      2640        ASL
      2650 .11    JSR UPDATE.TRACK.TABLE
      2660        PLA
      2670        JSR SEEK.TRACK
      2680        BCC .8       ...ALWAYS
      2690 .12    LDA HDR.SECTOR
      2700        CMP RWTS.SECTOR
      2710        BNE .9
      2720        LDA RWB.COMMAND
      2730        LSR
      2740        BCC .15           ...WRITE
      2750        JSR READ.SECTOR   ...READ
      2760        BCS .9            ...READ ERROR
      2770 .13    LDA #0       NO ERROR
      2780        .HS D0       "BNE"...NEVER, JUST SKIPS "SEC"
      2790 .14    SEC          ERROR
      2800        STA RWTS.ERROR    SAVE ERROR CODE
      2810        LDA DRV.MTROFF,X  STOP MOTOR
      2820        RTS               RETURN
      2830 *--------------------------------
      2840 .15    JSR WRITE.SECTOR
      2850 .16    BCC .13      ...NO ERROR
      2860        LDA #$2B     WRITE PROTECTED ERROR CODE
      2870        BNE .14      ...ALWAYS
      2880 .17    LDX SLOT.X16 CHECK IF WRITE PROTECTED
      2890        LDA DRV.Q6H,X
      2900        LDA DRV.Q7L,X
      2910        ROL
      2920        LDA DRV.Q6L,X
      2930        JMP .16      GIVE ERROR IF PROTECTED
      2940 *--------------------------------
      2950 SEEK.TRACK
      2960        ASL          GET PHYSICAL TRACK #
      2970        STA HDR.TRACK     ...SAVE HERE
      2980        JSR CLEAR.PHASES  (CARRY WAS CLEAR)
      2990        JSR GET.SSSD.IN.X
      3000        LDA OLD.TRACK.TABLE,X
      3010        STA CURRENT.TRACK
      3020        LDA HDR.TRACK
      3030        STA OLD.TRACK.TABLE,X
      3040        JSR SEEK.TRACK.ABSOLUTE
      3050 *--------------------------------
      3060 CLEAR.PHASES
      3070        LDY #3
      3080 .1     TYA
      3090        JSR PHASE.COMMANDER
      3100        DEY
      3110        BPL .1
      3120        LSR CURRENT.TRACK    BACK TO LOGICAL TRACK #
      3130        CLC          SIGNAL NO ERROR
      3140        RTS
      3150 *--------------------------------
      3160 SEEK.TRACK.ABSOLUTE
      3170        STA TARGET.TRACK  SAVE ACTUAL TRACK #
      3180        CMP CURRENT.TRACK ALREADY THERE?
      3190        BEQ .7            ...YES
      3200        LDA #0
      3210        STA STEP.CNT      # STEPS SO FAR
      3220 .1     LDA CURRENT.TRACK
      3230        STA CURRENT.TRACK.OLD
      3240        SEC
      3250        SBC TARGET.TRACK
      3260        BEQ .6            ...WE HAVE ARRIVED
      3270        BCS .2            CURRENT > DESIRED
      3280        EOR #$FF          CURRENT < DESIRED
      3290        INC CURRENT.TRACK
      3300        BCC .3            ...ALWAYS
      3310 .2     ADC #$FE          .CS., SO A=A-1
      3320        DEC CURRENT.TRACK
      3330 .3     CMP STEP.CNT GET MINIMUM OF:
      3340        BCC .4         1. # OF TRACKS TO MOVE LESS 1
      3350        LDA STEP.CNT   2. # OF STEPS SO FAR
      3360 .4     CMP #9         3. EIGHT
      3370        BCS .5
      3380        TAY
      3390        SEC          TURN NEW PHASE ON
      3400 .5     JSR .7
      3410        LDA ONTBL,Y  DELAY
      3420        JSR DELAY.100
      3430        LDA CURRENT.TRACK.OLD
      3440        CLC          TURN OLD PHASE OFF
      3450        JSR PHASE.COMMANDER
      3460        LDA OFFTBL,Y DELAY
      3470        JSR DELAY.100
      3480        INC STEP.CNT # OF STEPS SO FAR
      3490        BNE .1       ...ALWAYS
      3500 .6     JSR DELAY.100
      3510        CLC          TURN PHASE OFF
      3520 .7     LDA CURRENT.TRACK
      3530 *--------------------------------
      3540 *      (A) = TRACK #
      3550 *      .CC. THEN PHASE OFF
      3560 *      .CS. THEN PHASE ON
      3570 *--------------------------------
      3580 PHASE.COMMANDER
      3590        AND #3       ONLY KEEP LOWER TWO BITS
      3600        ROL               00000XXC
      3610        ORA SLOT.X16      0SSS0XXC
      3620        TAX
      3630        LDA DRV.PHASE,X
      3640        LDX SLOT.X16      RESTORE SLOT*16
      3650        RTS
      3660 *--------------------------------
      3670 *      VALUE READ FROM DISK IS INDEX INTO THIS TABLE
      3680 *      TABLE ENTRY GIVES TOP 6 BITS OF ACTUAL DATA
      3690 *
      3700 *      OTHER DATA TABLES ARE IMBEDDED IN THE UNUSED
      3710 *      PORTIONS OF THE BYTE.TABLE
      3720 *--------------------------------
      3730 BYTE.TABLE .EQ *-$96
      3740        .HS 0004FFFF080CFF101418
      3750 BIT.PAIR.LEFT
      3760        .HS 008040C0
      3770        .HS FFFF1C20FFFFFF24282C
      3780        .HS 3034FFFF383C4044
      3790        .HS 484CFF5054585C606468
      3800 BIT.PAIR.MIDDLE
      3810        .HS 00201030
      3820 DATA.TRAILER
      3830        .HS DEAAEBFF
      3840        .HS FFFFFF6CFF70
      3850        .HS 7478FFFFFF7CFFFF
      3860        .HS 8084FF888C9094989CA0
      3870 BIT.PAIR.RIGHT
      3880        .HS 0008040C
      3890        .HS FFA4A8ACFFB0B4B8BCC0
      3900        .HS C4C8FFFFCCD0D4D8
      3910        .HS DCE0FFE4E8ECF0F4
      3920        .HS F8FC
      3930 *--------------------------------
      3940 BIT.PAIR.TABLE
      3950        .HS 00000096
      3960        .HS 02000097
      3970        .HS 0100009A
      3980        .HS 0300009B
      3990        .HS 0002009D
      4000        .HS 0202009E
      4010        .HS 0102009F
      4020        .HS 030200A6
      4030        .HS 000100A7
      4040        .HS 020100AB
      4050        .HS 010100AC
      4060        .HS 030100AD
      4070        .HS 000300AE
      4080        .HS 020300AF
      4090        .HS 010300B2
      4100        .HS 030300B3
      4110        .HS 000002B4
      4120        .HS 020002B5
      4130        .HS 010002B6
      4140        .HS 030002B7
      4150        .HS 000202B9
      4160        .HS 020202BA
      4170        .HS 010202BB
      4180        .HS 030202BC
      4190        .HS 000102BD
      4200        .HS 020102BE
      4210        .HS 010102BF
      4220        .HS 030102CB
      4230        .HS 000302CD
      4240        .HS 020302CE
      4250        .HS 010302CF
      4260        .HS 030302D3
      4270        .HS 000001D6
      4280        .HS 020001D7
      4290        .HS 010001D9
      4300        .HS 030001DA
      4310        .HS 000201DB
      4320        .HS 020201DC
      4330        .HS 010201DD
      4340        .HS 030201DE
      4350        .HS 000101DF
      4360        .HS 020101E5
      4370        .HS 010101E6
      4380        .HS 030101E7
      4390        .HS 000301E9
      4400        .HS 020301EA
      4410        .HS 010301EB
      4420        .HS 030301EC
      4430        .HS 000003ED
      4440        .HS 020003EE
      4450        .HS 010003EF
      4460        .HS 030003F2
      4470        .HS 000203F3
      4480        .HS 020203F4
      4490        .HS 010203F5
      4500        .HS 030203F6
      4510        .HS 000103F7
      4520        .HS 020103F9
      4530        .HS 010103FA
      4540        .HS 030103FB
      4550        .HS 000303FC
      4560        .HS 020303FD
      4570        .HS 010303FE
      4580        .HS 030303FF
      4590 *--------------------------------
      4600 TBUF   .BS 86
      4610 *--------------------------------
      4620 RWTS.TRACK    .HS 07
      4630 RWTS.SECTOR   .HS 0F
      4640 RWTS.ERROR    .HS 00
      4650 OLD.SLOT      .HS 60
      4660 CURRENT.TRACK .HS 07
      4670               .HS 00
      4680 *--------------------------------
      4690 OLD.TRACK.TABLE .EQ *-4
      4700        .HS 0000     SLOT 2, DRIVE 0--DRIVE 1
      4710        .HS 0000     SLOT 3
      4720        .HS 0000     SLOT 4
      4730        .HS 0000     SLOT 5
      4740        .HS 0E00     SLOT 6
      4750        .HS 0000     SLOT 7
      4760 *--------------------------------
      4770        .HS 00
      4780 *--------------------------------
      4790 SEARCH.COUNT      .BS 1
      4800 SEEK.COUNT        .BS 1
      4810 STEP.CNT      .EQ *
      4820 SEEK.D5.CNT   .EQ *
      4830 X1X1X1X1          .BS 1   ALSO STEP.CNT & SEEK.D5.CNT
      4840 CHECK.SUM         .BS 1
      4850 HDR.CHKSUM        .BS 1
      4860 HDR.SECTOR        .BS 1
      4870 HDR.TRACK     .EQ *
      4880 MOTOR.TIME        .BS 2   ALSO HDR.TRACK & HDR.VOLUME
      4890 CURRENT.TRACK.OLD .BS 1
      4900 TARGET.TRACK      .BS 1
      4910 *--------------------------------
      4920 *      DELAY TIMES FOR ACCELERATION & DECELERATION
      4930 *      OF TRACK STEPPING MOTOR
      4940 *--------------------------------
      4950 ONTBL  .HS 01302824201E1D1C1C
      4960 OFFTBL .HS 702C26221F1E1D1C1C
      4970 *--------------------------------
      4980 *      DELAY ABOUT 100*A MICROSECONDS
      4990 *      RUN DOWN MOTOR.TIME WHILE DELAYING
      5000 *--------------------------------
      5010 DELAY.100
      5020 .1     LDX #17
      5030 .2     DEX
      5040        BNE .2
      5050        INC MOTOR.TIME
      5060        BNE .3
      5070        INC MOTOR.TIME+1
      5080 .3     SEC
      5090        SBC #1
      5100        BNE .1
      5110        RTS
      5120 *--------------------------------
      5130 READ.ADDRESS
      5140        LDY #$FC     TRY 772 TIMES TO FIND $D5
      5150        STY SEEK.D5.CNT        (FROM $FCFC TO $10000)
      5160 .1     INY
      5170        BNE .2       ...KEEP TRYING
      5180        INC SEEK.D5.CNT
      5190        BEQ .11      ...THAT IS ENUF!
      5200 .2     LDA DRV.Q6L,X     GET NEXT BYTE
      5210        BPL .2
      5220 .3     CMP #$D5     IS IT $D5?
      5230        BNE .1       ...NO, TRY AGAIN
      5240        NOP          ...YES, DELAY
      5250 .4     LDA DRV.Q6L,X     GET NEXT BYTE
      5260        BPL .4
      5270        CMP #$AA     NOW NEED $AA AND $96
      5280        BNE .3       ...NO, BACK TO $D5 SEARCH
      5290        LDY #3       (READ 3 BYTES LATER)
      5300 .5     LDA DRV.Q6L,X     GET NEXT BYTE
      5310        BPL .5
      5320        CMP #$96     BETTER BE...
      5330        BNE .3       ...IT IS NOT
      5340        SEI          ...NO INTERRUPTS NOW
      5350        LDA #0       START CHECK SUM
      5360 .6     STA CHECK.SUM
      5370 .7     LDA DRV.Q6L,X     GET NEXT BYTE
      5380        BPL .7       1X1X1X1X
      5390        ROL          X1X1X1X1
      5400        STA X1X1X1X1
      5410 .8     LDA DRV.Q6L,X     GET NEXT BYTE
      5420        BPL .8       1Y1Y1Y1Y
      5430        AND X1X1X1X1   XYXYXYXY
      5440        STA HDR.CHKSUM,Y
      5450        EOR CHECK.SUM
      5460        DEY
      5470        BPL .6
      5480        TAY          CHECK CHECKSUM
      5490        BNE .11      NON-ZERO, ERROR
      5500 .9     LDA DRV.Q6L,X     GET NEXT BYTE
      5510        BPL .9
      5520        CMP #$DE     TRAILER EXPECTED $DE.AA.EB
      5530        BNE .11      NO, ERROR
      5540        NOP
      5550 .10    LDA DRV.Q6L,X
      5560        BPL .10
      5570        CMP #$AA
      5580        BNE .11      NO, ERROR
      5590        CLC
      5600        RTS
      5610 .11    SEC
      5620        RTS
      5630 *--------------------------------
      5640 READ.SECTOR
      5650        TXA          SLOT*16 ($60 FOR SLOT 6)
      5660        ORA #$8C     BUILD Q6L ADDRESS FOR SLOT
      5670        STA .9+1     STORE INTO READ-DISK OPS
      5680        STA .12+1
      5690        STA .13+1
      5700        STA .15+1
      5710        STA .18+1
      5720        LDA RWB.BUFFER    PLUG CALLER'S BUFFER
      5730        LDY RWB.BUFFER+1  ADDRESS INTO STORE'S
      5740        STA .17+1    PNTR FOR LAST THIRD
      5750        STY .17+2
      5760        SEC          PNTR FOR MIDDLE THIRD
      5770        SBC #84
      5780        BCS .1
      5790        DEY
      5800 .1     STA .14+1
      5810        STY .14+2
      5820        SEC          PNTR FOR BOTTOM THIRD
      5830        SBC #87
      5840        BCS .2
      5850        DEY
      5860 .2     STA .11+1
      5870        STY .11+2
      5880 *---FIND $D5.AA.AD HEADER--------
      5890        LDY #32      MUST FIND $D5 WITHIN 32 BYTES
      5900 .3     DEY
      5910        BEQ .10      ERROR RETURN
      5920 .4     LDA DRV.Q6L,X
      5930        BPL .4
      5940 .5     EOR #$D5
      5950        BNE .3
      5960        NOP
      5970 .6     LDA DRV.Q6L,X
      5980        BPL .6
      5990        CMP #$AA
      6000        BNE .5
      6010        NOP
      6020 .7     LDA DRV.Q6L,X
      6030        BPL .7
      6040        CMP #$AD
      6050        BNE .5
      6060 *---READ 86 BYTES INTO TBUF...TBUF+85----------
      6070 *---THESE ARE THE PACKED LOWER TWO BITS--------
      6080 *---FROM EACH BYTE OF THE CALLER'S BUFFER.-----
      6090        LDY #170
      6100        LDA #0       INIT RUNNING EOR-SUM
      6110 .8     STA RUNNING.SUM
      6120 .9     LDX DRV.Q6L+MODIFIER  READ NEXT BYTE
      6130        BPL .9
      6140        LDA BYTE.TABLE,X      DECODE DATA
      6150        STA TBUF-170,Y
      6160        EOR RUNNING.SUM
      6170        INY
      6180        BNE .8
      6190 *---READ NEXT 86 BYTES-------------------------
      6200 *---STORE 1ST 85 IN BUFFER...BUFFER+84---------
      6210 *---SAVE THE 86TH BYTE ON THE STACK------------
      6220        LDY #170
      6230        BNE .12      ...ALWAYS
      6240 *--
      6250 .10    SEC          I/O ERROR EXIT
      6260        RTS
      6270 *--
      6280 .11    STA BUFF.BASE-171,Y
      6290 .12    LDX DRV.Q6L+MODIFIER  READ NEXT BYTE
      6300        BPL .12
      6310        EOR BYTE.TABLE,X      DECODE DATA
      6320        LDX TBUF-170,Y        MERGE LOWER 2 BITS
      6330        EOR BIT.PAIR.TABLE,X
      6340        INY
      6350        BNE .11
      6360        PHA          SAVE LAST BYTE (LATER BUFFER+85)
      6370 *---READ NEXT 86 BYTES-----------
      6380 *---STORE AT BUFFER+86...BUFFER+171------------
      6390        AND #$FC              MASK FOR RUNNING EOR.SUM
      6400        LDY #170
      6410 .13    LDX DRV.Q6L+MODIFIER  READ NEXT BYTE
      6420        BPL .13
      6430        EOR BYTE.TABLE,X      DECODE DATA
      6440        LDX TBUF-170,Y        MERGE LOWER 2 BITS
      6450        EOR BIT.PAIR.TABLE+1,X
      6460 .14    STA BUFF.BASE-84,Y
      6470        INY
      6480        BNE .13
      6490 *---READ NEXT 84 BYTES-------------------------
      6500 *---INTO BUFFER+172...BUFFER+255---------------
      6510 .15    LDX DRV.Q6L+MODIFIER  READ NEXT BYTE
      6520        BPL .15
      6530        AND #$FC
      6540        LDY #172
      6550 .16    EOR BYTE.TABLE,X      DECODE DATA
      6560        LDX TBUF-172,Y        MERGE LOWER 2 BITS
      6570        EOR BIT.PAIR.TABLE+2,X
      6580 .17    STA BUFF.BASE,Y
      6590 .18    LDX DRV.Q6L+MODIFIER  READ NEXT BYTE
      6600        BPL .18
      6610        INY
      6620        BNE .16
      6630        AND #$FC
      6640 *---END OF DATA------------------
      6650        EOR BYTE.TABLE,X      DECODE DATA
      6660        BNE .20           ...BAD CHECKSUM
      6670        LDX SLOT.X16      CHECK FOR TRAILER $DE
      6680 .19    LDA DRV.Q6L,X
      6690        BPL .19
      6700        CMP #$DE
      6710        CLC
      6720        BEQ .21           ...GOOD READ!
      6730 .20    SEC               ...SIGNAL BAD READ
      6740 .21    PLA               STORE BYTE AT BUFFER+85
      6750        LDY #85
      6760        STA (RWB.BUFFER),Y
      6770        RTS
      6780 *--------------------------------
      6790 UPDATE.TRACK.TABLE
      6800        JSR GET.SSSD.IN.X
      6810        STA OLD.TRACK.TABLE,X
      6820        RTS
      6830 *--------------------------------
      6840 CHECK.IF.MOTOR.RUNNING
      6850        LDX SLOT.X16
      6860 CHECK.IF.MOTOR.RUNNING.X
      6870        LDY #0
      6880 .1     LDA DRV.Q6L,X     READ CURRENT INPUT REGISTER
      6890        JSR .2            ...12 CYCLES...
      6900        PHA               ...7 MORE CYCLES...
      6910        PLA
      6920        CMP DRV.Q6L,X     BY NOW INPUT REGISTER
      6930        BNE .2            SHOULD HAVE CHANGED
      6940        LDA #$28     ERROR CODE: NO DEVICE CONNECTED
      6950        DEY          BUT TRY 255 MORE TIMES
      6960        BNE .1       ...RETURN .NE. IF MOVING...
      6970 .2     RTS          ...RETURN .EQ. IF NOT MOVING...
      6980 *--------------------------------
      6990 GET.SSSD.IN.X
      7000        PHA          SAVE A-REG
      7010        LDA RWB.SLOT     DSSSXXXX
      7020        LSR
      7030        LSR
      7040        LSR
      7050        LSR          0000DSSS
      7060        CMP #8       SET CARRY IF DRIVE 2
      7070        AND #7       00000SSS
      7080        ROL          0000SSSD
      7090        TAX          INTO X-REG
      7100        PLA          RESTORE A-REG
      7110        RTS
      7120 *--------------------------------
      7130 WRITE.SECTOR
      7140        SEC          IN CASE WRITE-PROTECTED
      7150        LDA DRV.Q6H,X
      7160        LDA DRV.Q7L,X
      7170        BPL .1       ...NOT WRITE PROTECTED
      7180        JMP WS.RET   ...PROTECTED, ERROR
      7190 *--------------------------------
      7200 .1     LDA TBUF
      7210        STA TBUF.0
      7220 *---WRITE 5 SYNC BYTES-----------
      7230        LDA #$FF
      7240        STA DRV.Q7H,X
      7250        ORA DRV.Q6L,X
      7260        LDY #4
      7270        NOP          $FF AT 40-CYCLE INTERVALS LEAVES
      7280        PHA          TWO ZERO-BITS AFTER EACH $FF
      7290        PLA
      7300 .2     PHA
      7310        PLA
      7320        JSR WRITE2
      7330        DEY
      7340        BNE .2
      7350 *---WRITE $D5 AA AD HEADER-------
      7360        LDA #$D5
      7370        JSR WRITE1
      7380        LDA #$AA
      7390        JSR WRITE1
      7400        LDA #$AD
      7410        JSR WRITE1
      7420 *---WRITE 86 BYTES FROM TBUF-------------------
      7430 *---BACKWARDS:   TBUF+85...TBUF+1, TBUF.0------
      7440        TYA          =0
      7450        LDY #86
      7460        BNE .4
      7470 .3     LDA TBUF,Y
      7480 .4     EOR TBUF-1,Y
      7490        TAX
      7500        LDA BIT.PAIR.TABLE+3,X
      7510        LDX SLOT.X16
      7520        STA DRV.Q6H,X
      7530        LDA DRV.Q6L,X
      7540        DEY
      7550        BNE .3
      7560        LDA TBUF.0
      7570 *---WRITE PORTION OF BUFFER------
      7580 *---UP TO A PAGE BOUNDARY--------
      7590        LDY #*-*     FILLED IN WITH LO-BYTE OF BUFFER ADDRESS
      7600 WS...5 EOR BUFF.BASE,Y   HI-BYTE FILLED IN
      7610        AND #$FC
      7620        TAX
      7630        LDA BIT.PAIR.TABLE+3,X
      7640 WS...6 LDX #MODIFIER
      7650        STA DRV.Q6H,X
      7660        LDA DRV.Q6L,X
      7670 WS...7 LDA BUFF.BASE,Y   HI-BYTE FILLED IN
      7680        INY
      7690        BNE WS...5
      7700 *---BRANCH ACCORDING TO BUFFER BOUNDARY CONDITIONS-----
      7710        LDA BYTE.AT.BUF00
      7720        BEQ WS..17   ...BUFFER ALL IN ONE PAGE
      7730        LDA INDEX.OF.LAST.BYTE
      7740        BEQ WS..16   ...ONLY ONE BYTE IN NEXT PAGE
      7750 *---MORE THAN ONE BYTE IN NEXT PAGE--------------------
      7760        LSR          ...DELAY TWO CYCLES
      7770        LDA BYTE.AT.BUF00  PRE.NYBBLE ALREADY ENCODED
      7780        STA DRV.Q6H,X      THIS BYTE
      7790        LDA DRV.Q6L,X
      7800        LDA BYTE.AT.BUF01
      7810        NOP
      7820        INY
      7830        BCS WS..12
      7840 WS...8 EOR BUFF.BASE+256,Y    HI-BYTE FILLED IN
      7850        AND #$FC
      7860        TAX
      7870        LDA BIT.PAIR.TABLE+3,X
      7880 WS...9 LDX #MODIFIER
      7890        STA DRV.Q6H,X
      7900        LDA DRV.Q6L,X
      7910 WS..10 LDA BUFF.BASE+256,Y    HI-BYTE FILLED IN
      7920        INY
      7930 WS..11 EOR BUFF.BASE+256,Y    HI-BYTE FILLED IN
      7940 WS..12 CPY INDEX.OF.LAST.BYTE
      7950        AND #$FC
      7960        TAX
      7970        LDA BIT.PAIR.TABLE+3,X
      7980 WS..13 LDX #MODIFIER
      7990        STA DRV.Q6H,X
      8000        LDA DRV.Q6L,X
      8010 WS..14 LDA BUFF.BASE+256,Y    HI-BYTE FILLED IN
      8020        INY
      8030        BCC WS...8
      8040        BCS .15      ...3 CYCLE NOP
      8050 .15    BCS WS..17   ...ALWAYS
      8060 *---WRITE BYTE AT BUFFER.00---------------------------
      8070 WS..16 .DA #$AD,BYTE.AT.BUF00    4 CYCLES: LDA BYTE.AT.BUF00
      8080        STA DRV.Q6H,X
      8090        LDA DRV.Q6L,X
      8100        PHA
      8110        PLA
      8120        PHA
      8130        PLA
      8140 WS..17 LDX LAST.BYTE
      8150        LDA BIT.PAIR.TABLE+3,X
      8160 WS..18 LDX #MODIFIER
      8170        STA DRV.Q6H,X
      8180        LDA DRV.Q6L,X
      8190        LDY #0
      8200        PHA
      8210        PLA
      8220 *---WRITE DATA TRAILER:  $DE AA EB FF----------
      8230        NOP
      8240        NOP
      8250 .19    LDA DATA.TRAILER,Y
      8260        JSR WRITE3
      8270        INY
      8280        CPY #4
      8290        BNE .19
      8300        CLC          SIGNAL NO ERROR
      8310 WS.RET LDA DRV.Q7L,X     DRIVE TO SAFE MODE
      8320        LDA DRV.Q6L,X
      8330        RTS
      8340 *--------------------------------
      8350 WRITE1 CLC
      8360 WRITE2 PHA
      8370        PLA
      8380 WRITE3 STA DRV.Q6H,X
      8390        ORA DRV.Q6L,X
      8400        RTS
      8410 *--------------------------------
      8420 PRE.NYBBLE
      8430        LDA RWB.BUFFER    PLUG IN ADDRESS TO LOOP BELOW
      8440        LDY RWB.BUFFER+1
      8450        CLC
      8460        ADC #2
      8470        BCC .1
      8480        INY
      8490 .1     STA PN...6+1
      8500        STY PN...6+2
      8510        SEC
      8520        SBC #$56
      8530        BCS .2
      8540        DEY
      8550 .2     STA PN...5+1
      8560        STY PN...5+2
      8570        SEC
      8580        SBC #$56
      8590        BCS .3
      8600        DEY
      8610 .3     STA PN...4+1
      8620        STY PN...4+2
      8630 *---PACK THE LOWER TWO BITS INTO TBUF-------------
      8640        LDY #170
      8650 PN...4 LDA BUFF.BASE-170,Y   ADDRESS FILLED IN
      8660        AND #3
      8670        TAX
      8680        LDA BIT.PAIR.RIGHT,X
      8690        PHA
      8700 PN...5 LDA BUFF.BASE-84,Y
      8710        AND #3
      8720        TAX
      8730        PLA
      8740        ORA BIT.PAIR.MIDDLE,X
      8750        PHA
      8760 PN...6 LDA BUFF.BASE+2,Y
      8770        AND #3
      8780        TAX
      8790        PLA
      8800        ORA BIT.PAIR.LEFT,X
      8810        PHA
      8820        TYA
      8830        EOR #$FF
      8840        TAX
      8850        PLA
      8860        STA TBUF,X
      8870        INY
      8880        BNE PN...4
      8890 *---DETERMINE BUFFER BOUNDARY CONDITIONS----------
      8900 *---AND SETUP WRITE.SECTOR ACCORDINGLY------------
      8910        LDY RWB.BUFFER
      8920        DEY
      8930        STY INDEX.OF.LAST.BYTE
      8940        LDA RWB.BUFFER
      8950        STA WS...5-1
      8960        BEQ .7
      8970        EOR #$FF
      8980        TAY
      8990        LDA (RWB.BUFFER),Y
      9000        INY
      9010        EOR (RWB.BUFFER),Y
      9020        AND #$FC
      9030        TAX
      9040        LDA BIT.PAIR.TABLE+3,X
      9050 .7     STA BYTE.AT.BUF00    =0 IF BUFFER NOT SPLIT
      9060        BEQ .9
      9070        LDA INDEX.OF.LAST.BYTE
      9080        LSR
      9090        LDA (RWB.BUFFER),Y
      9100        BCC .8
      9110        INY
      9120        EOR (RWB.BUFFER),Y
      9130 .8     STA BYTE.AT.BUF01
      9140 .9     LDY #$FF
      9150        LDA (RWB.BUFFER),Y
      9160        AND #$FC
      9170        STA LAST.BYTE
      9180 *---INSTALL BUFFER ADDRESSES IN WRITE.SECTOR------
      9190        LDY RWB.BUFFER+1
      9200        STY WS...5+2
      9210        STY WS...7+2
      9220        INY
      9230        STY WS...8+2
      9240        STY WS..10+2
      9250        STY WS..11+2
      9260        STY WS..14+2
      9270 *---INSTALL SLOT*16 IN WRITE.SECTOR---------------
      9280        LDX SLOT.X16
      9290        STX WS...6+1
      9300        STX WS...9+1
      9310        STX WS..13+1
      9320        STX WS..18+1
      9330        RTS
      9340 *--------------------------------
      9350 WAIT.FOR.OLD.MOTOR.TO.STOP
      9360        EOR OLD.SLOT      SAME SLOT AS BEFORE?
      9370        ASL               (IGNORE DRIVE)
      9380        BEQ .2            ...YES
      9390        LDA #1       LONG MOTOR.TIME
      9400        STA MOTOR.TIME+1  (COUNTS BACKWARDS)
      9410 .1     LDA OLD.SLOT
      9420        AND #$70
      9430        TAX
      9440        BEQ .2       ...NO PREVIOUS MOTOR RUNNING
      9450        JSR CHECK.IF.MOTOR.RUNNING.X
      9460        BEQ .2       ...NOT RUNNING YET
      9470        LDA #1       DELAY ANOTHER 100 USECS
      9480        JSR DELAY.100
      9490        LDA MOTOR.TIME+1
      9500        BNE .1       KEEP WAITING
      9510 .2     RTS
      9520 *--------------------------------
      9530        .BS $FF9B-*       <<<<EMPTY SPACE>>>>
      9540 *--------------------------------
      9550 IRQ
      9560        PHA          SAVE A-REG
      9570        LDA $45     SAVE LOC $45
      9580        STA SAVE.LOC45
      9590        PLA          SAVE A-REG AT LOC $45
      9600        STA $45
      9610        PLA          GET STATUS BEFORE IRQ
      9620        PHA
      9630        AND #$10     SEE IF "BRK"
      9640        BNE .2       ...YES, LET MONITOR DO IT
      9650        LDA $D000    SAVE $D000 BANK ID
      9660        EOR #$D8
      9670        BEQ .1
      9680        LDA #$FF
      9690 .1     STA INTBANKID
      9700        STA SAVE.D000
      9710        LDA #$BF     PUSH FAKE "RTI" VECTOR WITH
      9720        PHA               IRQ DISABLED
      9730        LDA #$50          AND SET TO RETURN TO $BF50
      9740        PHA
      9750        LDA #4
      9760        PHA
      9770 .2     LDA #$FA     PUSH "RTS" VECTOR FOR MONITOR
      9780        PHA
      9790        LDA #$41
      9800        PHA
      9810 CALL.MONITOR
      9820        STA $C082    SWITCH TO MOTHERBOARD
      9830 *--------------------------------
      9840 RESET
      9850        LDA RESET.VECTOR+1
      9860        PHA          PUSH "RTS" VECTOR FOR MONITOR
      9870        LDA RESET.VECTOR
      9880        PHA
      9890        JMP CALL.MONITOR
      9900 *--------------------------------
      9910 RESET.VECTOR
      9920        .DA $FA61    MON.RESET-1
      9930 *--------------------------------
      9940 INT.SPLICE
      9950        STA INTAREG
      9960        LDA SAVE.LOC45
      9970        STA $45
      9980        LDA $C08B    SWITCH TO MAIN $D000 BANK
      9990        LDA SAVE.D000
      10000        JMP IRQXIT.3
      10010 *--------------------------------
      10020        .BS $FFFA-*       <<<<<EMPTY SPACE>>>>>
      10030 *--------------------------------
      10040 V.NMI      .DA $03FB
      10050 V.RESET    .DA RESET
      10060 V.IRQ      .DA IRQ
      10070 *--------------------------------

More Assembly Listing into Text Files | Tracy L. ShaferMacDill AFB, FL

In the October '83 issue of AAL, Robert F. O'Brien presented a way to create a text file containing the assembly listing of a large program. (See also "Assembly Listing Into a Text File", by Bill Morgan, July '83 AAL.) Actually, he created several text files; one for each .IN directive in the root file. You can't put the whole listing into one text file by using one .TF directive because of the way the .IN directive affects the DOS I/O hooks.

Robert's method for obtaining assembly listing text files is good, but I found a different way to create the text files of assembly listings that doesn't involve creating separate SYMBOLS sections, deleting duplicate labels, and putting up with "EXTRA DEFINITIONS ERROR" messages. It's a fairly simple approach and hinges on the fact that the problem presented by the .IN directive affects the source file containing the .IN, but not the source file to which the .IN refers. Instead of putting one .TF directive in the root file, put a .TF in each source file pointed to by a .IN directive.

For example:

            ROOT FILE

            1000    .DU
            1010    .IN PART 1
            1020    .IN PART 2
            1030    .ED

            PART 1

            1000    .TF LISTING 1
            1010    (source for part 1)

            PART 2

            1000    .TF LISTING 2
            1010    (source for part 2)

From here on, follow Bill Morgan's original instructions. What follows is a summary of those instructions.

After deleting all other .TF directives, or turning them into comments by inserting "*" at the beginning of the line, typing ASM will create two binary files named LISTING 1 and LISTING 2. Each of these contains the assembly listing of PART 1 and PART 2 respectively, in text form. These binary files will not have starting address and length in the first four bytes. DO NOT attempt to BLOAD these files. You could really clobber DOS. To obtain true text files, make the following patch to the S-C Assembler before you assemble the program:

            $1000 versions:  $29DF:0  (original value is 04)
            $D000 versions:  $C083 C083 EAF9:0 N C083

After the patch is made, assemble the program and restore the original value to $29DF ($EAF9).

For really large programs, it could get very tedious adding a .TF directive to each sub-file to obtain a text file listing and then deleting those .TF directives to prevent messing up the object file the next time the program is assembled. Fortunately, the S-C Macro Assembler's conditional assembly feature makes our work a lot easier. By placing an equated flag in the root file and surrounding each .TF with .DO and .FIN, we only have to change one line to set up our program for text file output or object file creation. For example:

            ROOT FILE

            1000 LSTOUT .EQ 0       TO ASSEMBLE OBJECT
            1010 *          1       TO OUTPUT TEXT FILES
            1020        .DO LSTOUT
            1040        .DU
            1050        .ELSE
            1060        .TF OBJECT FILE
            1070        .FIN
            1080        .IN PART 1
            1090        .IN PART 2
            1100        .DO LSTOUT
            1110        .ED
            1120        .FIN

            PART 1

            1000        .DO LSTOUT
            1010        .TF LISTING 1
            1020        .FIN
            1030        (source for part 1)

            PART 2

            1000        .DO LSTOUT
            1010        .TF LISTING 2
            1020        .FIN
            1030        (source for part 2)

Don't forget to patch $29DF ($EAF9 for the language card version) with 0 to output true text files and back to 04 create object files. The last thing to remember is to use .LIST ON during the assembly. You won't write any text files if the assembler isn't producing a listing.

Note on Aztec C | Bill Morgan

I just talked to the people at Manx Software about the ProDOS version of their C compiler, and this time they assured me that owners of the current Apple DOS version will be able to purchase the ProDOS version at a reduced upgrade price. That is enough to tip the balance in favor of buying the compiler right now, so I have ordered some. List price is $199: we'll have them for $180 + shipping.

Generalized GOTO and GOSUB | Bob Sander-Cederlof

Tim Mowchanuk, a lecturer at Brisbane College in Australia, sent the following suggestion:

> "How can I implement a named GOTO or GOSUB routine? There are numerous routines that implement computed GOTO/GOSUB, but I consider that a futile exercise. Computed GOTO/GOSUB mess up renumbering utilities, and violate modern trends toward structured programming.

> "What I really want is something that will handle BASIC like

>            100 & GOSUB NAME$

> where NAME$ holds the name of a subroutine. I envision subroutine names being defined by a special REM statement of the form

>            200 REM "SUBROUTINE NAME"

> The &GOSUB or &GOTO processor can search through the program for a line beginning with a REM token. If the first non-blank after the REM token is a quotation mark, the processor can compare the characters to the string value. If there is an exact match, the line containing the REM is the target for the &GOTO or &GOSUB."

The problem sounded just the right size for an interesting AAL article, so I started trying to write some code.

I published an &GOSUB routine back in April 1981 of the type that Tim thinks futile. The following program combines the two "futile" computed &GOSUB and &GOTO routines with two new ones that allow the computed value to be a string expression. If the expression after &GOTO or &GOSUB is numeric, the processor will search for a matching line number. If the result is a string, the processor will search for a REM label as Tim described above.

Only REM's at the beginning of a numbered line will be considered as labels. The label must be included in quotation marks. Spaces are OK between the word REM and the first quotation mark. Anything after the second quotation mark will be ignored.

You can now write a menu program that uses the actual command word as the name of a subroutine, and cease worrying about line numbers. The accompanying Applesoft program is an example of just such a technique.

         100  PRINT  CHR$ (4)"BLOAD B.LABELLED GO'S": CALL 768
         1000  DATA  SEND,RECEIVE,EDIT,LOAD,SAVE,EXIT,.
         1010 I = 0
         1020 I = I + 1: READ A$(I): IF A$(I) <  > "." THEN 1020
         1030 N = I - 1
         1100  INPUT C$:I = 0
         1110 I = I + 1: IF C$ = A$(I) THEN  &  GOSUB C$: GOTO 1100
         1120  IF I < N THEN 1110
         1130  PRINT "NO SUCH COMMAND": GOTO 1100
         2000  REM "SEND"
         2010  PRINT "SEND NOT YET IMPLEMENTED"
         2020  RETURN
         2500  REM "RECEIVE"
         2510  PRINT "RECEIVE IS NOT READY"
         2520  RETURN
         3000  REM "EDIT"
         3010  PRINT "MAYBE YOU CAN EDIT LATER"
         3020  RETURN
         3500  REM "LOAD"
         3510  PRINT "LOAD WHAT, WHERE, HOW?"
         3520  RETURN
         4000  REM "SAVE"
         4010  PRINT "SAVE WHAT, WHERE, HOW"
         4020  RETURN
         4500  REM "EXIT"
         4510  PRINT "AH!  THAT I CAN DO!"
         4520  POP : END

      1000 *SAVE S.LABELLED GO'S
      1010 *--------------------------------
      1020 *      & GOTO <STR EXP>
      1030 *      & GOSUB<STR EXP>
      1040 *      REM "<LABEL>"
      1050 *
      1060 *      AS SUGGESTED BY TIM MOWCHANUK
      1070 *--------------------------------
      1080 AS.VALTYP  .EQ $11
      1090 AS.TEMPPT  .EQ $52,53
      1100 INDEX.REM  .EQ $5E
      1110 INDEX.GO   .EQ $5F
      1120 PRGBOT     .EQ $67,68
      1130 AS.CURLIN  .EQ $75,76
      1140 PNTR       .EQ $9B,9C
      1150 STRLEN     .EQ $9D
      1160 STRADR     .EQ $9E,9F
      1170 VPNT       .EQ $A0,A1
      1180 TXTPTR     .EQ $B8,B9
      1190 *--------------------------------
      1200 TKN.GOTO   .EQ $AB
      1210 TKN.GOSUB  .EQ $B0
      1220 TKN.REM    .EQ $B2
      1230 *--------------------------------
      1240 AMPERSAND.VECTOR .EQ $3F5 ... 3F7
      1250 *--------------------------------
      1260 AS.CHRGET  .EQ $00B1
      1270 AS.CHRGOT  .EQ $00B7
      1280 AS.MEMCHK  .EQ $D3D6
      1290 AS.NEWSTT  .EQ $D7D2
      1300 AS.GOTO1   .EQ $D941
      1310 AS.GOTO.3  .EQ $D95E
      1320 AS.UNDERR  .EQ $D97C
      1330 AS.FRMEVL  .EQ $DD7B
      1340 AS.SYNERR  .EQ $DEC9
      1350 AS.FRETMP  .EQ $E604
      1360 AS.GETADR  .EQ $E752
      1370 *--------------------------------
      1380        .OR $300
      1390        .TF B.LABELLED GO'S
      1400 *--------------------------------
      1410 SETUP  LDA #LABELLED.GOTO.AND.GOSUB
      1420        STA AMPERSAND.VECTOR+1
      1430        LDA /LABELLED.GOTO.AND.GOSUB
      1440        STA AMPERSAND.VECTOR+2
      1450        RTS
      1460 *--------------------------------
      1470 LABELLED.GOTO.AND.GOSUB
      1480        JSR AS.CHRGOT
      1490        CMP #TKN.GOTO
      1500        BEQ .3
      1510        CMP #TKN.GOSUB
      1520        BEQ .2       ...GOOD SYNTAX SO FAR
      1530 .1     JMP AS.SYNERR
      1540 *---SETUP GOSUB RETURN DATA------
      1550 .2     LDA #3
      1560        JSR AS.MEMCHK
      1570        LDA TXTPTR+1
      1580        PHA
      1590        LDA TXTPTR
      1600        PHA
      1610        LDA AS.CURLIN+1
      1620        PHA
      1630        LDA AS.CURLIN
      1640        PHA
      1650        LDA #TKN.GOSUB
      1660        PHA
      1670        BNE .4       ...ALWAYS
      1680 *---SETUP FOR GOTO---------------
      1690 .3     PLA          POP RETURN TO "NEWSTT"
      1700        PLA
      1710 *---FIND LABEL AFTER TOKEN-------
      1720 .4     JSR AS.CHRGET
      1730        BEQ .1
      1740        JSR AS.FRMEVL     EVALUATE EXPRESSION
      1750        BIT AS.VALTYP     $00 IF NUMERIC, $FF IF STRING
      1760        BMI .5            ...STRING
      1770 *---NUMERIC EXPRESSION-----------
      1780        JSR AS.GETADR     CONVERT TO INTEGER
      1790        JSR AS.GOTO1
      1800        JMP AS.NEWSTT
      1810 *---FREE ANY TEMP STRINGS--------
      1820 .45    LDA AS.TEMPPT+1
      1830        LDY #0
      1840        JSR AS.FRETMP
      1850 .5     LDA AS.TEMPPT
      1860        CMP #$56     EMPTY?
      1870        BCS .45      ...NO, FREE A STRING
      1880 *---COPY STRING LENGTH/ADDRESS---
      1890        LDY #2
      1900 .55    LDA (VPNT),Y
      1910        STA STRLEN,Y
      1920        DEY
      1930        BPL .55
      1940 *---SEARCH PROGRAM FOR LABEL-----
      1950        LDA PRGBOT+1      POINT TO BEGINNING
      1960        LDX PRGBOT           OF PROGRAM
      1970 *---LOOK AT NEXT LINE------------
      1980 .6     STA PNTR+1   UPDATE PNTR TO NEXT LINE
      1990        STX PNTR
      2000        LDY #1       HI-BYTE OF FWD PNTR
      2010        LDA (PNTR),Y
      2020        BEQ .11      ...END OF PROGRAM
      2030 *---CHECK FOR 'REM "'------------
      2040        LDY #4
      2050        LDA (PNTR),Y
      2060        CMP #TKN.REM
      2070        BNE .10      ...NOT REM STATEMENT
      2080 .7     INY          NEXT BYTE OF LINE
      2090        LDA (PNTR),Y
      2100        CMP #' '     IGNORE BLANKS BEFORE "
      2110        BEQ .7
      2120        CMP #'"'     " YET?
      2130        BNE .10      ...NO, NOT A LABEL
      2140 *---COMPARE LABEL----------------
      2150        STY INDEX.REM
      2160        LDA #-1
      2170        STA INDEX.GO
      2180 .8     INC INDEX.REM
      2190        LDY INDEX.REM
      2200        LDA (PNTR),Y
      2210        BEQ .1       ...EARLY END OF LABEL
      2220        INC INDEX.GO
      2230        LDY INDEX.GO
      2240        CMP #'"'     LEGAL END OF LABEL?
      2250        BEQ .9       ...YES
      2260        CMP (STRADR),Y
      2270        BEQ .8       ...KEEP MATCHING
      2280        BNE .10      ...DOESN'T MATCH
      2290 .9     CPY STRLEN   CORRECT LENGTH?
      2300        BNE .10      ...NO, KEEP SEARCHING
      2310 *---FOUND LABEL, SO GO TO IT-----
      2320        JSR AS.GOTO.3
      2330        JMP AS.NEWSTT
      2340 *---DOESN'T MATCH, TRY NEXT LINE-
      2350 .10    LDY #0       GET FORWARD POINTER
      2360        LDA (PNTR),Y      LO-BYTE
      2370        TAX
      2380        INY               HI-BYTE
      2390        LDA (PNTR),Y
      2400        BNE .6       ...NOT END OF PROGRAM YET
      2410 *---END OF PROGRAM, UNDEF LBL----
      2420 .11    JMP AS.UNDERR

Timemaster II from Applied Engineering | Bob Sander-Cederlof

It may come as a surprise (it did to me), but there are apparently now only three calendar/clocks still on the market for the Apple II, II Plus, //e. The others, and there were a lot of them, seemed to have dropped off the map. And even one of the three (Mountain Computer) does not advertise anywhere I can find.

Another surprise: the most expensive clock has the fewest features, and the least expensive has the most features.

Mountain Computer Apple Clock:

> $280 in current catalog listing; most recent ad I could find was in Jan 1980 Byte, at $199. Features below are guessed at from ad and conversations with Dan Pote. Works with BASIC only, does not include any DOS Dater or ProDOS support.

> Gives month, day of month, hour, minute, second, millisecond

> Interrupt available: Second, Millisecond

Thunderware Thunderclock Plus:

> Gives month, day of month, day of week, hour, minute, second.

> $150 with BASIC software for DOS or ProDOS $ 29 extra for Pascal software $ 29 extra for DOS-DATER/DEMO disk

> Interrupts available: 64, 256, or 2048 times per second

> Applied Engineering Timemaster:

> $129 includes Applesoft support for DOS or ProDOS includes Pascal and CP/M support includes DOS Dater

> Gives year, month, day of month, day of week, hour, minute, second

> Interrupts available: Millisecond, Second, Minute, Hour. Switchable to either NMI or IRQ interrupt line.

For some reason they have not chosen to explain, the wizards at Apple who created ProDOS decided to "wire in" support for the Thunderclock (and ONLY Thunderclock). A system call reads the time and date from Thunderclock, calculates the year from the given information, and stores year-month-day-hour-minute in a packed format at $BF90...BF93. ProDOS automatically records time/date of creation and time/date of last modification.

In order to get the year with these dates, ProDOS goes through a calculation to derive year from given day of month, month, and day of week information. The calculation involves remaindering and table lookup...but it only works from 1982 through 1987. I suppose by 1988 they will have generated a new version which works beyond, or else we won't care anymore. Better yet, by 1988 maybe they will have driver-ized the clock support so we can use Dan's card directly.

Dan Pote sent me a Timemaster to play with, in hopes that I would figure out how to make it look like a Thunderclock to ProDOS. I did, so if you buy one now it will be completely compatible with ProDOS. You select by DIP Switch which page of the onboard EPROM will be mapped into the $CN00 space (where N is slot 1-7). One setting selects the ProDOS section, and the others select various versions designed for use with DOS and Applesoft.

You can talk to Dan's card directly, as well as through the EPROM. If you don't like the way his firmware works (unlikely), you can either ignore it or change it.

(By the way.... Call A.P.P.L.E., a club/magazine with a penchant for value and quality, has chosen to offer another one of Applied Engineering's boards in its latest catalog: the Viewmaster 80. Their price is $140, which is 20% below normal retail.)

Finding Trouble in a Big RAM Card | Bob Sander-Cederlof

Last night (Monday, Nov 28th) I took home an Apple to do some spreadsheet work. I took home the most portable one, but first swapped RAM cards. I took the STB-128 out of my oldest Apple and put it into the Apple II Plus with the fewest attachments.

When I plugged it in at home and booted the spreadsheet program, all appeared to be well. But it wasn't. I loaded in a model, and during the re-calculation the spreadsheet program hit a BRK opcode and died. I pressed RESET and looked at the partially re-calculated sheet: it was sprinkled with nonsense characters, and the keyboard was locked up. I played with various combinations for an hour or so, including other programs which use the RAM card. Everything pointed to there being a bad bit somewhere in the card.

Of course the RAM card test program was back at the office. I decided to write another one rather than face the two mile round trip.

The 128K space on the STB-128 is divided into 8 banks. You select a bank by storing a bank number (0-7) at any address in the $C080+slot*16 space which has bit 2 = 1. For slot 0, that means store in $C080, $C081, $C082, $C083, $C088, $C089, $C08A, or $C08B. The card has three green LEDs on top which show which bank is currently selected.

Each 16K bank is further divided to fit into the 12K address space between $D000 and $FFFF. The softswitch controlled by bit 3 in the $C08x address selects which of two 4K banks will be enabled at $D000-DFFF. The other 8K always sits at $E000-FFFF. A red LED signals which $D000 bank is selected.

The low-order two bits of the $C08x address control the mode of the RAM card. Accessing $C080 or $C088 write protects the card, and read enables it. This means the $D000-FFFF references the RAM card rather than the motherboard ROM. Accessing $C082 or $C08A write protects the RAM card and disables reading it; in other words, it switches on the motherboard ROM.

$C081 or $C089 also turn on the mother board ROM for reading, but if you access one of these twice in a row it will write enable the RAM card. In this mode reads reference the motherboard ROM, but writes write into the RAM card. This mode is used when loading the RAM card so that monitor and Applesoft routines which are in motherboard ROM can be used for the loading process.

Accessing $C083 or $C08B once read enables the STB-128 card and write protects it. A second access write enables the card. This is the mode we use for a memory test.

Thinking about how to test such a card, I wrote down the following "flow chart":

           For Bank = 0 to 7
               Store Bank in $C083
               Access $C083 again to write enable
                   Test $D000-DFFF
               Access $C08B twice
                   Test $D000-FFFF
           Next Bank

I broke the actual testing of a range of memory into four parts. First I stored zeroes into every location, and checked to be sure I read zeroes back. Then I did the same with $FF. Then, $55. Then, $AA. This is certainly not an exhaustive test, but I hoped it would be sufficient.

The tricky part was informing myself of the locations and values involved of any memory errors found during the test. I could not conveniently use the monitor subroutines to write addresses and values on the screen, because the monitor only existed in the motherboard ROM and it was switched off! So, I wrote a quick and dirty display routine.

The routine for display in the listing below is not quite so "quick and dirty". The program starts by clearing the screen using the monitor HOME subroutine at $FC58. Then it switches to the RAM card and runs the test. The program pokes test failure data directly to the screen. I direct the data for each of the 8 banks to a different line. When a failure occurs, I print the address, the value that should have been there, the actual value found, and the exclusive-or of the two values. The exclusive-or shows me which bit or bits was incorrect.

After running the test it was obvious that the least significant bit in banks 5 and 6 was not working. When it should be zero it was sometimes one, and vice versa.

I did not know which chip on the STB-128 card belonged to which bit slice or which bank, so I guessed. I was lucky, and guessed right the first time. I pulled out the chip I thought might be the bad one, and re-ran the test. This time the test indicated the least significant bit of banks 4-7 was missing. (It happened to be the chip in the lower-left corner when looking at the face of the card.)

I put the chip back in, hoping that it would miraculously heal itself. Then I looked at the back of the board to see if anything looked suspicious there. Sure enough! STB did not trim off the excess length of the socket pins after soldering the board. One of those long pins had bent over and was possibly shorted to another, on the lower left socket. I straightened the pin and re-ran the test. Voila! It passed!

After I finished patting myself on the back I tried to run the spreadsheet again. It still failed! This morning I put the cards back in their usual homes, and everything works fine.

Tuesday Afternoon....Lo and behold, the card is still bad. I found the STB Systems diskette, and ran their RAM test program. It identified the same chip as being bad. But after running the test for several hours, the errors stopped. Obviously the chip's problems are intermittent.

Wednesday Morning....The chip is still giving errors. I called STB and they said to bring the board by. Wednesday afternoon....STB replaced the chip, and all is well.

      1000  .LIF
      1010 *SAVE S.TEST STB-128
      1020 *--------------------------------
      1030 *      TEST STB-128
      1040 *--------------------------------
      1050 YSAVE  .EQ 0
      1060 LIMIT  .EQ 1
      1070 ADDR   .EQ 2,3
      1080 BANK   .EQ 4
      1090 BYTE   .EQ 5
      1100 SCREEN .EQ 6,7
      1110 *--------------------------------
      1120 SELECT .EQ $C080
      1130 *--------------------------------
      1140 TTTT   JSR TEST
      1150        JSR TEST
      1160        JSR TEST
      1170        JSR TEST
      1180        RTS
      1190 *--------------------------------
      1200 TEST   LDA #0
      1210        STA BANK
      1220        STA ADDR
      1230        JSR $FC58    CLEAR SCREEN
      1240        LDA #$04
      1250        STA SCREEN+1
      1260        LDA #$28
      1270        STA SCREEN
      1280 *---SELECT BANK------------------
      1290 .1     LDA BANK
      1300        STA SELECT+$07
      1310        ORA #$B0     CONVERT TO SCREEN ASCII
      1320        LDY #0
      1330        STA (SCREEN),Y
      1340        LDA SELECT+$03
      1350 *---TEST D000...DFFF-------------
      1360        LDA #$E0
      1370        STA LIMIT
      1380        JSR TEST.ZEROS
      1390        JSR TEST.ONES
      1400        JSR TEST.FIVES
      1410        JSR TEST.AYES
      1420 *---SWITCH TO OTHER D000---------
      1430        LDA SELECT+$0B
      1440        LDA SELECT+$0B
      1450 *---TEST D000...FFFF-------------
      1460        LDA #0
      1470        STA LIMIT
      1480        JSR TEST.ZEROS
      1490        JSR TEST.ONES
      1500        JSR TEST.FIVES
      1510        JSR TEST.AYES
      1520 *---NEXT BANK--------------------
      1530        LDA SCREEN
      1540        EOR #$80
      1550        STA SCREEN
      1560        BMI .2
      1570        INC SCREEN+1
      1580 .2     INC BANK
      1590        LDA BANK
      1600        CMP #8
      1610        BCC .1
      1620 *---SWITCH TO ROMS---------------
      1630        LDA SELECT+$01
      1640        RTS
      1650 *--------------------------------
      1660 TEST.ZEROS
      1670        LDA #0
      1680        .HS 2C
      1690 TEST.ONES
      1700        LDA #$FF
      1710        .HS 2C
      1720 TEST.FIVES
      1730        LDA #$55
      1740        .HS 2C
      1750 TEST.AYES
      1760        LDA #$AA
      1770        STA BYTE
      1780        LDA #$D0
      1790        STA ADDR+1
      1800 .1     JSR FILL
      1810        JSR COMPARE
      1820        INC ADDR+1
      1830        LDA ADDR+1
      1840        CMP LIMIT
      1850        BNE .1
      1860        RTS
      1870 *--------------------------------
      1880 FILL   LDY #0
      1890        LDA BYTE
      1900 .1     STA (ADDR),Y
      1910        INY
      1920        BNE .1
      1930        RTS
      1940 *--------------------------------
      1950 COMPARE
      1960        LDY #0
      1970 .1     LDA (ADDR),Y
      1980        CMP BYTE
      1990        BNE .3
      2000 .2     INY
      2010        BNE .1
      2020        RTS
      2030 .3     PHA          SAVE ACTUAL DATA
      2040        STY YSAVE    SAVE Y-REG
      2050        LDA ADDR+1   PRINT ADDRESS OF FAILURE
      2060        LDY #2
      2070        JSR CONBYTE
      2080        LDA YSAVE    LO-BYTE OF ADDRESS
      2090        JSR CONBYTE
      2100        INY
      2110        LDA BYTE     WHAT DATA SHOULD HAVE BEEN
      2120        JSR CONBYTE
      2130        INY
      2140        PLA          WHAT DATA REALLY WAS
      2150        PHA          KEEP ON STACK TOO
      2160        JSR CONBYTE
      2170        INY
      2180        PLA          FIGURE WHICH BITS WERE WRONG
      2190        EOR BYTE
      2200        JSR CONBYTE
      2210        LDY #0       DELAY LOOP TO SLOW THINGS DOWN
      2220 .4     DEY          FOR OBSERVATION
      2230        BNE .4
      2240        LDY YSAVE
      2250        JMP .2       REJOIN TEST
      2260 *--------------------------------
      2270 CONBYTE
      2280        PHA
      2290        LSR
      2300        LSR
      2310        LSR
      2320        LSR
      2330        JSR CONNYBBLE
      2340        PLA
      2350 CONNYBBLE
      2360        AND #$0F
      2370        CMP #10
      2380        BCC .1
      2390        ADC #6
      2400 .1     ADC #$B0
      2410        STA (SCREEN),Y
      2420        INY
      2430        RTS
      2440 *--------------------------------

Procedure for Converting S-C Source Files to Text Files Without Owning an S-C Assembler | Bob Sander-Cederlof

Strangely enough, there are some of you who still do not own an S-C Assembler. And some of you buy or would like to buy our Quarterly Disks or the Applesoft Docu-Mentor disks.

These disks contain source files which are only usable by the S-C Macro Assembler. However, it is possible (even without an S-C Assembler) to convert them to regular text files so as to be readable by another brand assembler/editor.

The files appear in the catalog as type "I", which is supposed to mean Integer BASIC. Of course the contents has nothing to do with Integer BASIC, but making them "I-files" has several advantages:

- they LOAD/SAVE faster than text files
- standard DOS commands can be used for load/save
- when the S-C Assembler is in the RAM card, DOS can automatically switch between Applesoft and Assembler as it normally would between Applesoft and Integer BASIC.

There are also some dis-advantages:

- some users have trouble believing they are not really Integer BASIC programs, and try to RUN them.
- the files are harder for people without an S-C Assembler to convert to another brand.

Which brings us back to the point of this article.

To make the procedure simple, you need at least a 64K Apple. If you have an Apple //e, you are all set. An older Apple needs a "language card", or "RAM card".

The first step in the conversion process is to load the file into memory and find out where it is. Start by booting with your DOS 3.3 System Master disk, which loads Integer BASIC into the RAM card. Then LOAD the S-C source file which you want to convert. Integer BASIC will be switched on, but don't try to LIST or RUN!

Enter the Monitor by typing "CALL -151". At this point you will get an asterisk prompt. Look at locations $4C, $4D, $CA, and $CB. You can do it like this:

           *4C.4D CA.CB
           004C- 00 96
           00CA- 58 73

Interpret the above as meaning that the source code begins in memory at $7358 and ends one byte before $9600.

If you use the monitor commands to look at the first 30 or 40 bytes (or more), you will discover how the source lines are stored. Each line begins with a byte count, which if added to the address will give the address of the first byte of the next line. Each line ends with a 00 byte. The byte count includes both of these bytes, and all in between. Here is a sample line:

           0F E8 03 41 42 43 84 4C 44 41 81 23 24 35 00

The second and third bytes are the binary form of the line number. As usual in 6502 domain, the number is stored low-byte first. $3E8 means the line above is line 1000.

The fourth byte and beyond are ASCII codes for the text of the line, with two exceptions. If the bytes are less than $80, they are plain ASCII. If they are in the range from $81 through $BF, they represent a series of blanks. $81 means one blank, $84 means four blanks, and so on. The line above now decodes to:

           1000 ABC    LDA #$5

The other exception is not illustrated above, but here is one:

           08 F2 03 2A C0 20 2D 00

The token $C0 means "repeated character". The next byte after $C0 gives the number of repetitions, and the byte after that tells what character to repeat. Above the C0 20 2D means 32 "-" characters, so the whole line looks like this:

           1010 *--------------------------------

Armed with all that information, you can probably see how to write a simple Applesoft program to convert the memory image of the S-C source file to plain text and then write it on a text file.

In fact, here is just such a program:

         100  REM CONVERT MEMORY IMAGE OF S-C SOURCE
         110  REM TO ORDINARY TEXT FILE
         200 HM =  PEEK (76) + 256 *  PEEK (77)
         210 PP =  PEEK (768) + 256 *  PEEK (769)
         220  HIMEM: PP
         300  REM OPEN A TEXT FILE
         310 D$ =  CHR$ (4)
         320  PRINT D$"OPEN TEXTFILENAME": PRINT D$"DELETE TEXTFILENAME"
         330  PRINT D$"OPEN TEXTFILENAME": PRINT D$"WRITE TEXTFILENAME"
         400 L = PP
         410  IF L = HM THEN  PRINT D$"CLOSE": END
         420  GOSUB 500: REM  DO ONE LINE
         430  GOTO 410
         500  REM DO ONE SOURCE LINE
         510 N =  PEEK (L)
         520 LN =  PEEK (L + 1) + 256 *  PEEK (L + 2): PRINT LN" ";:L = L +
              2
         530 L = L + 1:C =  PEEK (L): IF C = 0 THEN  PRINT :L = L + 1: RETURN
         540  IF C < 128 THEN  PRINT  CHR$ (C);: GOTO 530
         550  IF C < 192 THEN  FOR I = 1 TO C - 128: PRINT " ";: NEXT : GOTO
              530
         560  IF C = 192 THEN  FOR I = 1 TO  PEEK (L + 1): PRINT  CHR$ ( PEEK
              (L + 2));: NEXT I:L = L + 2: GOTO 530
         570  PRINT : PRINT D$"CLOSE": PRINT "***ERROR IN SOURCE AT "L"***
              ": END

Here is a blow-by-blow description of how to use the program.

1. Boot your DOS System Master to load INTBASIC into the RAM card.
2. Load the S-C source file.
3. Type CALL-151 to get into the monitor.
4. Type CA.CB to get the starting address of the S-C source program (xx yy).
5. Type 300:xx yy to store the starting address in a place Applesoft will not clobber.
6. Type 3D0G to return to Integer BASIC.
7. Type RUN CONVERT S-C TO TEXT to execute the Applesoft program listed above.
8. Stand back and wait while the program chugs through the bytes. When you see the Applesoft prompt again, it is all done!

If you add a line at 315 to turn on MONCIO, you can see the text as it is produced.

Where To?, Revisited | Bill Morgan

Many thanks to all of you who responded to my questions about 68000, C, and the future of Apple Assembly Line.

Your answers ran about eight to one in favor of including 68000 information in AAL. Several writers suggested starting with a few pages, and possibly splitting off a separate newletter someday. That sounds like a good plan, so we'll start a regular section next issue. Those of you who already know 68000 can now start teaching the rest of us. Bob Urschel has already sent in a brief article and program! He has a QWERTY Q68 board like that we reviewed last month, and speaks very highly of it.

Interest in Macintosh (Apple 32?) is growing rapidly: the announcement is expected at the Apple shareholder meeting in mid-January. Some reports claim that some developers have had Mac for up to 18 months now. We haven't been among those so privileged, but I hope to be the first on my block with one. (Unless the thing turns out to have some fatal flaw, like no expansion slots. That was one rumor!)

Several of you also expressed an interest in C, but not even a majority. More like 30%. It looks like a number of people are curious, but feel that too much coverage would dilute AAL. Stephen Bach said it best, "... don't spread yourselves too thin and try to do C also." I expect to do occasional reviews and mentions of books and other aids to learning C, and to report on anything specifically related to C on Apple computers, but not much more.

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 $15 per year in the USA, sent Bulk Mail; add $3 for First Class postage in USA, Canada, and Mexico; add $13 postage for other countries. Back issues are available for $1.50 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.)