In This Issue...
New ProDOS Book
Dennis Doms and Tom Weishaar, Technical Consultant and Publisher of Open-Apple, have conspired to bring us an interesting new book on programming under ProDOS, especially focussing on BASIC.SYSTEM.
"ProDOS Inside and Out" begins by explaining what an operating system is, progresses by describing files and directories, and goes on into simple commands. The next sections cover Applesoft programming and text file handling, followed by information about using machine language under BASIC.SYSTEM and using the ProDOS Kernel and MLI calls from BASIC.
This book does an excellent job of introducing the basic concepts of ProDOS, and then takes the reader on into quite advanced territory. It's very refreshing to find a book that doesn't assume you're already an expert and still has enough substance to help make you into one.
"ProDOS Inside and Out", by Dennis Doms and Tom Weishaar, from TAB Books. List is $16.95, we'll have it for $16 + shipping.
Of course, there are always eight bits in a byte, by definition. But sometimes we want to know how many of those eight bits are 1's. There are enough reasons to generate this count that some computers have a special machine language opcode to count the number of 1-bits in a byte or word.
One reason that comes to mind is to compute the odd- or even-parity bit for a byte of ASCII data. Another is in processing of picture data in a computer vision system.
I came up with at least eight different programs to count the 1-bits in a byte. I would choose one based on how critical speed or memory-usage is in a particular case.
The fastest one, table lookup, can translate a byte to a bit count in 4 cycles (7 if you also count getting the byte-value into X or Y. It is fast, but it requires a 256-byte table. The table has the counts for each possible value. If speed is critical, I would use this method. I would probably use one of the other methods to create the table during initialization, rather than assembling it from source code. An example of the table lookup method is shown in lines 2130-2160, as a subroutine.
The next method that I thought of is shown in lines 1500-1590. I count the 1-bits in the X-register, while shifting the data byte. The loop runs eight times, once for each bit position. This one takes from 86 cycles to 94 cycles, depending on how many 1-bits there are. The average time is 90 cycles. (I am not counting the JSR and RTS.)
A slightly faster method checks two bit positions during each loop (lines 1610-1730). The reduction in loop overhead changes the times to minimun 66, maximum 74, average 70 cycles.
The fastest method I found without table lookup is shown in lines 1750-2010. This one is completely unwrapped, so there is no loop overhead at all. The times come out to minimum 43, maximum 51, average 47 cycles.
I tried just optimizing the first method, and lines 2030-2110 are the result. This one gets more average speed because it loops only until there are no more 1-bits left. The minimum is only 8 cycles (when the byte = $00). If the byte = $80, it takes 14 cycles. For $C0 or $40, it takes 128 or 120 cycles. For values that have bit 0 = 1, it will take from 70 to 77 cycles, depending on the number of 1-bits in the other seven bit positions. The overall average is 65 cycles.
By changing this last method just a little, the overall average can be reduced to between 58 and 59 cycles. The result is still fairly small, so I think this one would be may favorite choice when the blinding speed of a table lookup is not necessary:
COUNT LDX #0 LDA BYTE BEQ .3 value is 00000000 BPL .2 bit 7 = 0 .1 INX count the 1-bit .2 ASL shift the value BMI .1 ...its 1, count it BNE .2 ...its 0, do not count .3 RTS finished
Lines 2270-2460 implement still another method, which always takes 57 cycles regardless of the mix of zeroes and ones. It uses an extra pagezero location for a temporary cell. The TAX in line 2450 is required only if it is really required that the bit count be returned in the X-register. My test program has this requirement, but there is no reason to force that requirement on a real program. If the A-register is good enough, then this method only takes 55 cycles.
Lines 2180-2250 are "half" a table lookup. That is, I am using half a table: entries for values from $00 to $7F. This is a tiny bit slower than the full table lookup, but saves 128 bytes of table. I shift the value right one bit position, guaranteeing a value from $00 to $7F, and save the bit shifted out in carry. Then adding carry to the value from the table gives me the count for the whole original value. A slight change to how carry is added can reduce the average time by half a cycle:
COUNT LDA BYTE LSR TAY LDX TBL1,Y BCC .1 INX .1 RTS
The wildest way I came up with is based on one I read about in the latest issue of Byte magazine (the IBM special issue, in the BIX section). By masking, adding, and shifting, the bits can be all aligned and added into a count. Lines 2480-2720 are my code for this method. The time is 58 cycles, regardless of the 0/1 mix.
I wrote a test routine, so I could tell whether my methods really worked or not. Lines 1070-1480 call each of three different bit-counters for every possible value of the byte. It keeps calling the first method until I hit the space bar, and then advances to the second method. Then it keeps calling the second, until another key-tap advances it to the third method. I can keep cycling through the methods this way, until I type a RETURN to end it. Inside each of the three loops I have a "LDA $C030" instruction, to toggle the speaker. The three loops are identical in timing except for the bit-counting code itself. The result is that I can tell by "ear" which methods are fastest, and which ones have a constant time regardless of the 0/1 mix. I tested the accuracy by comparing the results in TBL1 and TBL2 with the monitor "V" command, and by displaying the TBL using the monitor.
1000 *SAVE S.BIT COUNTERS 1010 *-------------------------------- 1020 BYTE .EQ $00 1030 B .EQ $01 1040 SUM1 .EQ $01 1050 SUM2 .EQ $02 1060 *-------------------------------- 1070 T 1080 LDA #0 1090 STA BYTE 1100 *-------------------------------- 1110 .1 JSR COUNT.1 1120 LDY BYTE 1130 TXA 1140 STA TBL1,Y 1150 LDA $C030 1160 INC BYTE 1170 LDA $C000 1180 BPL .1 1190 STA $C010 1200 CMP #$8D 1210 BEQ .99 1220 *-------------------------------- 1230 .2 JSR COUNT.2 1240 LDY BYTE 1250 TXA 1260 STA TBL2,Y 1270 LDA $C030 1280 INC BYTE 1290 LDA $C000 1300 BPL .2 1310 STA $C010 1320 CMP #$8D 1330 BEQ .99 1340 *-------------------------------- 1350 .3 JSR COUNT.3 1360 LDY BYTE 1370 TXA 1380 STA TBL2,Y 1390 LDA $C030 1400 INC BYTE 1410 LDA $C000 1420 BPL .3 1430 STA $C010 1440 CMP #$8D 1450 BEQ .99 1460 *-------------------------------- 1470 JMP .1 1480 .99 RTS 1490 *-------------------------------- 1500 COUNT.1 1510 LDY #8 TEST 1 BIT AT A TIME, 1520 LDX #0 LOOPING 8 TIMES 1530 LDA BYTE 1540 .1 ASL IF BIT = 1, COUNT IT 1550 BCC .2 1560 INX 1570 .2 DEY 1580 BNE .1 NEXT BIT 1590 RTS 1600 *-------------------------------- 1610 COUNT.2 1620 LDY #4 TEST 2 BITS AT A TIME, 1630 LDX #0 LOOPING 4 TIMES 1640 LDA BYTE 1650 .1 ASL 1660 BPL .2 IF BIT = 1, COUNT IT 1670 INX 1680 .2 BCC .3 IF BIT = 1, COUNT IT 1690 INX 1700 .3 ASL 1710 DEY 1720 BNE .1 NEXT PAIR OF BITS 1730 RTS 1740 *-------------------------------- 1750 COUNT.3 1760 LDX #0 NO LOOPS, JUST STRAIGHT-LINE CODE 1770 LDA BYTE 1780 BPL .1 BIT 7 1790 INX 1800 .1 LSR 1810 BCC .2 BIT 0 1820 INX 1830 .2 LSR 1840 BCC .3 BIT 1 1850 INX 1860 .3 LSR 1870 BCC .4 BIT 2 1880 INX 1890 .4 LSR 1900 BCC .5 BIT 3 1910 INX 1920 .5 LSR 1930 BCC .6 BIT 4 1940 INX 1950 .6 LSR 1960 BCC .7 BIT 5 1970 INX 1980 .7 LSR 1990 BCC .8 BIT 6 2000 INX 2010 .8 RTS 2020 *-------------------------------- 2030 COUNT.4 2040 LDX #0 2050 LDA BYTE 2060 BEQ .3 2070 .1 BPL .2 2080 INX 2090 .2 ASL 2100 BNE .1 2110 .3 RTS 2120 *-------------------------------- 2130 COUNT.5 2140 LDY BYTE 2150 LDX TBL1,Y 2160 RTS 2170 *-------------------------------- 2180 COUNT.6 2190 LDA BYTE 2200 LSR 2210 TAX 2220 LDA #0 2230 ADC TBL1,X 2240 TAX 2250 RTS 2260 *-------------------------------- 2270 COUNT.7 2280 LDA BYTE 3 2290 LSR BIT 0 2 2300 STA B 3 2310 LDA #0 2 2320 ROL 2 2330 LSR B BIT 1 5 2340 ADC #0 2350 LSR B BIT 2 2360 ADC #0 2370 LSR B BIT 3 2380 ADC #0 2390 LSR B BIT 4 2400 ADC #0 2410 LSR B BIT 5 2420 ADC #0 2430 LSR B BIT 6 2440 ADC B BIT 7 2450 TAX 2460 RTS 2470 *-------------------------------- 2480 COUNT.8 2490 LDA BYTE 2500 AND #$55 BITS 6,4,2,0 2510 STA SUM1 2520 EOR BYTE BITS 7,5,3,1 2530 LSR CLEARS CARRY 2540 ADC SUM1 FORM wwxxyyzz, where each pair 2550 STA SUM1 is 0, 1, or 2. 2560 AND #$33 Isolate 00xx00zz 2570 STA SUM2 2580 EOR SUM1 Isolate ww00yy00 2590 LSR 2600 LSR Now it is 00ww00yy 2610 ADC SUM2 Form 0uuu0vvv, where each group 2620 STA SUM2 is 0, 1, 2, 3, or 4. 2630 AND #$0F Isolate 00000vvv 2640 STA SUM1 2650 EOR SUM2 Isolate 0uuu0000 2660 LSR 2670 LSR 2680 LSR 2690 LSR Now it is 00000uuu 2700 ADC SUM1 Form count 0-8 2710 TAX 2720 RTS 2730 *-------------------------------- 2740 .BS *+255/256*256-* 2750 *-------------------------------- 2760 TBL1 .BS 256 2770 TBL2 .BS 256 2780 *-------------------------------- |
Somewhere I ran across a statement that the 128K bytes of ROM in the //gs have a standard checksum. A value is stored at $FFFFF6 and $FFFFF7 to pad out the checksum, so that it will always add up to $1234. I tried various ways of adding up the bytes to get that value, and came up with the following little program.
1000 *SAVE S.CHECKSUM 1010 *-------------------------------- 1020 .OP 65816 1030 *-------------------------------- 1040 FORM.AND.DISPLAY.IIGS.CHECKSUM 1050 CLC ENTER NATIVE MODE 1060 XCE 1070 REP #$30 FULL 16 1080 *-------------------------------- 1090 LDX ##0 0 TO FFFF 1100 TXA START WITH A=0 1110 SEC WHY? IT MAKES ANSWER $1234 1120 .1 ADC $FE0000,X BANK $FE 1130 INX 1140 INX TWO BYTES AT A TIME 1150 BNE .1 ...UNTIL WHOLE BANK 1160 .2 ADC $FF0000,X BANK $FF 1170 INX 1180 INX TWO BYTES AT A TIME 1190 BNE .2 ...UNTIL WHOLE BANK 1200 STA 0 SAVE RESULT AT $00,01 1210 *-------------------------------- 1220 SEC EMULATION MODE 1230 XCE 1240 LDA 1 PRINT CHECKSUM WITH OLD MONITOR 1250 JSR $FDDA SUBROUTINE 'PRBYTE' 1260 LDA 0 1270 JSR $FDDA 1280 RTS 1290 *-------------------------------- |
The 128K ROM occupies the space from $FE0000 through $FFFFFF. My program adds up the data there two bytes at a time in 16-bit registers. Doing a normal add of these "words" gave a sum of $1233, so I started with SEC instead of CLC to get a sum of $1234. I took my program to a computer store and tried it on a "real" //gs, with a different ROM set, and got the same result: $1234.
If you make any changes to the ROMs yourself, be sure to fix the checksum too. Otherwise you may not even be able to boot!
You can see a list of the names of the people inside Apple who worked on the //gs by typing in the following program. The names are stored inside the //gs ROM, organized according to which project they worked on. I suppose future versions of the //gs ROMs may not have this information (they may need the space for more useful tools), or it may be moved around, but so far it is all the machines I have looked at.
The names start at $BA0B, and are in two consecutive blocks terminated by a 00 byte. Most of the bytes are ASCII characters with bit 7 high (=1). Whenever you find a byte with bit 7 low (=0), it is a repeat count for the following character. Thus 07 A0 means repeat $A0 seven times, or print seven blanks. You will also find repeat counts followed by $53, which is an inverse S. However, in MouseText, it is a horizontal line. Evidently it is supposed to be displayed with MouseText turned on.
There may be a program somewhere inside the ROM that prints the list of names, but I haven't even tried finding it yet. Anyway, the following one will do it.
1000 *SAVE S.NAMES.IIGS 1010 *-------------------------------- 1020 * PRINT NAMES OF APPLE //GS DEVELOPERS 1030 *-------------------------------- 1040 .OP 65816 1050 *-------------------------------- 1060 PRINT.NAMES.OF.APPLE.PEOPLE 1080 CLC ENTER NATIVE MODE 1090 XCE 1100 REP #$10 X,Y 16-BIT MODE 1101 LDA #$8D SKIP TWO LINES 1102 JSR MY.COUT 1103 JSR MY.COUT 1110 LDX ##$BA0A NAMES START AT $BA0B 1120 JSR PRINT.NAMES FIRST BLOCK 1130 JSR PRINT.NAMES SECOND BLOCK 1140 SEC 1150 XCE BACK TO NATIVE MODE 1190 RTS 1200 *-------------------------------- 1210 PRINT.NAMES 1220 .1 INX NEXT CHAR 1230 LDA $FF0000,X 1240 BEQ .2 ...END OF A BLOCK 1250 BPL .3 ...REPEAT COUNT 1260 JSR MY.COUT PRINT THE CHAR 1270 BRA .1 1280 .2 RTS RETURN 1290 *-------------------------------- 1320 .3 TAY REPEAT COUNT TO Y-REG 1340 INX 1350 LDA $FF0000,X GET REPEATED CHAR 1351 CMP #$53 MOUSE TEXT LINE? 1352 BNE .4 ...NO 1353 LDA #"-" ...YES, SUBSTITUTE DASH 1360 .4 JSR MY.COUT PRINT THE CHAR 1370 DEY N TIMES 1380 BNE .4 1390 BRA .1 1400 *-------------------------------- 1410 MY.COUT 1420 PHA SAVE EVERYTHING!!! 1430 PHX 1440 PHY 1450 PHP 1460 SEC EMULATION MODE 1470 XCE 1480 PHP 1490 JSR $FDED 1500 PLP ORIGINAL MODE 1510 XCE 1520 PLP RESTORE REGISTERS 1530 PLY 1540 PLX 1550 PLA 1560 RTS 1570 *-------------------------------- 1580 .LIF |
What happens when you call ProDOS MLI? In assembly language, MLI calls look like this:
JSR $BF00 .DA #command,IOB.Address
The instruction at $BF00 is a "JMP $BFB7" in ProDOS 1.1.1; it is possibly different in other versions. All of the following disassembly is for ProDOS 1.1.1. The changes in the new ProDOS 1.2 are minor, and if you have 1.2 you should be able to figure out what they are.
At $BFB7 there is some code I call LC.BRIDGE.ENTRY. It "remembers" what language card areas are switched in at $D000 and at $E000, and then turns on the language card so that it can jump into the MLI call processor.
BFB7: SEC Set flag ROR MLI.ACTIVE.FLAG LDA $E000 STA E000.BYTE (BFF4) LDA $D000 STA D000.BYTE (BFF5) LDA $C08B LDA $C08B JMP $DE00
Now comes the good part. The following listing is of the code starting at $DE00, which decodes the bytes following your JSR $BF00 and performs your request.
Lines 1010-1080 define some page-zero variables used by MLI. Lines 1090-1220 define some items in the system global page. Lines 1230-1280 define some entry points inside the rest of MLI, not listed here.
MLI calls don't change the X and Y registers, so they are saved at line 1390. The return address (of the JSR $BF00) is pulled off the stack and saved at PARM.PNTR in page zero, so that it can be used to access your command code and IOB address. Lines 1410-1490 also compute the address of the next instruction, to be used later for a return address. This address is saved in the system global page, and is useful sometimes for debugging. (We have published several articles on enhanced error messages and tracers for MLI calls in previous issues of AAL.)
Lines 1500-1650 convert the command code to an index by a strange scheme. The legal command codes are (in hex): 40, 41, 65, 80 thru 82, and C0 thru D3. The hashing algorithm used here adds the high nybble of the command code to the whole code, and then masks it to the lower five bits. This compresses the range of the codes, without any overlapping.
40,41 --> 04,05 C0-CF --> 0C-1B 65 --> 0B D0-D2 --> 1D-1F 80-82 --> 08-0A D3 --> 00
This index is used then to look into the COMMAND.HASH.TABLE, which has the actual command codes in the indexed positions. If the original code is not found there, then the original code was an illegal command number. The hash index is also used to look up the parameter count in PARM.CNT.TABLE. I have appended the code for these two tables to the end of today's listing, at lines 3100 to the end.
Lines 1810-1920 branch various ways according to the command code. Most of the commands are not shown in this listing, but most of the code for READ BLOCK and WRITE BLOCK is shown (lines 2690-3080). When a command is finished, it eventually finds its way back to EXIT.TO.CALLER at line 2180.
Lines 2180-2560 get us back to our own code again, after the JSR $BF00. If the MLI call produced an error, the code number for that error will be in SYS.ERRNUM. The error code will be returned in the A-register, with carry SET. If there is no error to report, A=0 and carry is clear.
We will probably be presenting more sections of MLI disassembly in the near future. You may remember that we published portions of an earlier ProDOS version back in November and December of 1983.
1000 *SAVE S.MLI.DE00.DEF2 1010 *-------------------------------- 1020 PARM.PNTR .EQ $40,41 1030 COMMAND .EQ $42 1040 UNIT.NO .EQ $43 1050 BUFF.PNTR .EQ $44,45 1060 BLOCK.NO .EQ $46,47 1070 GEN.PNTR1 .EQ $48,49 1080 GEN.PNTR2 .EQ $4E,4F 1090 *-------------------------------- 1100 CALL.QUIT .EQ $BF03 1110 CALL.TIME .EQ $BF06 1120 CALL.SYSERR .EQ $BF09 1130 SYS.ERRNUM .EQ $BF0F 1140 DRIVER.ADDR.TABLE .EQ $BF10 thru BF2F 1150 BACKUP.BIT .EQ $BF95 1160 MLI.ACTIVE.FLAG .EQ $BF9B 1170 MLI.RETURN .EQ $BF9C,D 1180 MLI.X .EQ $BF9E 1190 MLI.Y .EQ $BF9F 1200 LC.BRIDGE.EXIT .EQ $BFA0 1210 E000.BYTE .EQ $BFF4 1220 D000.BYTE .EQ $BFF5 1230 *-------------------------------- 1240 INTERRUPT.HANDLER .EQ $DEF3 1250 FILING.FUNCTIONS .EQ $E047 1260 CHECK.IF.MEM.FREE .EQ $FC9F 1270 *-------------------------------- 1280 JUMP .EQ $FEF5,6 1290 *-------------------------------- 1300 .OR $DE00 1310 .TA $800 1320 *-------------------------------- 1330 * JSR $BF00 comes here 1340 * .DA #$xx command byte 1350 * .DA xxxx IOB Address 1360 *-------------------------------- 1370 MLI.ENTRY 1380 CLD 1390 STY MLI.Y 1400 STX MLI.X 1410 PLA GET RETURN ADDRESS 1420 STA PARM.PNTR WILL POINT AT BYTES 1430 CLC FOLLOWING JSR $BF00 1440 ADC #4 COMPUTE ACTUAL RETURN 1450 STA MLI.RETURN AND SAVE FOR LATER 1460 PLA 1470 STA PARM.PNTR+1 1480 ADC #0 1490 STA MLI.RETURN+1 1500 *---Check Command Code----------- 1510 LDY #0 1520 STY SYS.ERRNUM 1530 INY 1540 LDA (PARM.PNTR),Y 1550 LSR Hash it (CC/16 + CC) & $1F 1560 LSR 1570 LSR 1580 LSR 1590 CLC 1600 ADC (PARM.PNTR),Y 1610 AND #$1F 1620 TAX Use hashcode as index 1630 LDA (PARM.PNTR),Y Original command code 1640 CMP COMMAND.HASH.TABLE,X 1650 BNE ERR.CALL.NO Not valid command 1660 *---Get IOB Address-------------- 1670 INY 1680 LDA (PARM.PNTR),Y 1690 PHA 1700 INY 1710 LDA (PARM.PNTR),Y 1720 STA PARM.PNTR+1 1730 PLA 1740 STA PARM.PNTR 1750 *---Check Parm Count------------- 1760 LDY #0 1770 LDA PARM.CNT.TABLE,X 1780 BEQ MLI.GETTIME ...only one with 0 parms 1790 CMP (PARM.PNTR),Y 1800 BNE ERR.PARM.CNT 1810 *---Branch Various Ways---------- 1820 LDA COMMAND.HASH.TABLE,X 1830 CMP #$65 1840 BEQ .1 ...QUIT CALL 1850 ASL 1860 BPL MLI.RWBLK $80 or $81 1870 BCS MLI.CX.AND.DX $Cx or $Dx 1880 LSR $40 or $41 1890 AND #$03 1900 JSR INTERRUPT.HANDLER 1910 JMP EXIT.TO.CALLER 1920 .1 JMP CALL.QUIT $65 1930 *-------------------------------- 1940 * Command $82, Get the Date and Time 1950 *-------------------------------- 1960 MLI.GETTIME 1970 JSR CALL.TIME 1980 JMP EXIT.TO.CALLER 1990 *-------------------------------- 2000 * Commands $80 and $81 2010 *-------------------------------- 2020 MLI.RWBLK 2030 LSR Make $00 and 01 2040 ADC #1 Into $01 and 02 2050 STA COMMAND Store into command block 2060 JSR BLOCK.IO.SETUP Do the I/O 2070 JMP EXIT.TO.CALLER 2080 *-------------------------------- 2090 * Commands $C0 thru $D3 2100 *-------------------------------- 2110 MLI.CX.AND.DX 2120 LSR Make command code into 2130 AND #$1F an index 2140 TAX 2150 JSR FILING.FUNCTIONS 2160 *---fall into EXIT routine------- 2170 * (DE78) DE5A DE63 DE6E DEB0 callers 2180 EXIT.TO.CALLER 2190 LDA #0 Clear BACKUP bit 2200 STA BACKUP.BIT 2210 LDY SYS.ERRNUM If any error code, 2220 CPY #1 then set carry 2230 TYA and clear Z-bit 2240 PHP Save this status 2250 SEI Disable IRQ's 2260 LSR MLI.ACTIVE.FLAG Clear this flag 2270 PLA Get saved status 2280 TAX and keep it in X-reg 2290 LDA MLI.RETURN+1 2300 PHA Put return address on stack 2310 LDA MLI.RETURN 2320 PHA 2330 TXA Now push the status for RTI 2340 PHA 2350 TYA Get error code in A-reg 2360 LDX MLI.X Restore X and Y 2370 LDY MLI.Y 2380 PHA Error code on stack 2390 LDA E000.BYTE 2400 JMP LC.BRIDGE.EXIT 2410 *-------------------------------- 2420 * LC.BRIDGE.EXIT is code at $BFA0 in 2430 * the system global page. It restores 2440 * the language card to the state it 2450 * was in when JSR $BF00 was exectuted. 2460 *-------------------------------- 2470 * LC.BRIDGE.EXIT EOR $E000 2480 * BEQ .1 BFAA 2490 * STA $C082 2500 * BNE .2 BFB5 2510 * .1 LDA D000.BYTE $BFF5 2520 * EOR $D000 2530 * BEQ .2 BFB5 2540 * LDA $C083 2550 * .2 PLA 2560 * RTI 2570 *-------------------------------- 2580 ERR.NO.DEVICE 2590 LDA #$28 "NO DEVICE CONNECTED" 2600 JSR CALL.SYSERR 2610 ERR.CALL.NO 2620 LDA #1 "BAD CALL TYPE" 2630 BNE DEAD 2640 ERR.PARM.CNT 2650 LDA #4 "BAD PARAMETER COUNT" 2660 DEAD JSR CALL.CALL.SYSERR 2670 BCS EXIT.TO.CALLER ...ALWAYS 2680 *-------------------------------- 2690 BLOCK.IO.SETUP 2700 LDY #5 COPY REST OF COMMAND BLOCK 2710 PHP FROM IOB TO ZERO-PAGE 2720 SEI DO NOT ALLOW IRQ'S 2730 .1 LDA (PARM.PNTR),Y 2740 STA COMMAND,Y 2750 DEY 2760 BNE .1 2770 LDX BUFF.PNTR+1 2780 STX GEN.PNTR2+1 2790 INX 2800 INX 2810 LDA BUFF.PNTR 2820 BEQ .2 2830 INX 2840 .2 JSR CHECK.IF.MEM.FREE 2850 BCS .3 ...NOT FREE 2860 JSR BLOCK.IO 2870 BCS .3 ...I/O ERROR 2880 PLP RESTORE IRQ STATUS 2890 CLC NO ERRORS 2900 RTS 2910 *-------------------------------- 2920 .3 PLP RESTORE IRQ STATUS 2930 CALL.CALL.SYSERR JSR CALL.SYSERR 2940 *-------------------------------- 2950 * (DEDA) DECE EC0A EE83 F0E4 F475 callers 2960 BLOCK.IO 2970 LDA UNIT.NO Clean this up a little 2980 AND #$F0 2990 STA UNIT.NO 3000 LSR Make it into index too 3010 LSR 3020 LSR 3030 TAX 3040 LDA DRIVER.ADDR.TABLE,X 3050 STA JUMP 3060 LDA DRIVER.ADDR.TABLE+1,X 3070 STA JUMP+1 3080 JMP (JUMP) 3090 *-------------------------------- 3100 .OR $FD65 3110 .TA $800 3120 COMMAND.HASH.TABLE 3130 .HS D3.00.00.00.40.41.00.00 3140 .HS 80.81.82.65.C0.C1.C2.C3 3150 .HS C4.C5.C6.C7.C8.C9.CA.CB 3160 .HS CC.CD.CE.CF.00.D0.D1.D2 3170 PARM.CNT.TABLE 3180 .HS 02.FF.FF.FF.02.01.FF.FF 3190 .HS 03.03.00.04.07.01.02.07 3200 .HS 0A.02.01.01.03.03.04.04 3210 .HS 01.01.02.02.FF.02.02.02 3220 *-------------------------------- 3230 .LIF |
The following refers back to the new ProDOS Quit Code I wrote and published in the July 86 issue of AAL. It has been very popular, judging from the number of letters and phone calls we have received.
Eric Trehus (T'n'T Software) pointed out that I ignored one or more of the conventions Apple established for Quit-Code Program Selectors. On page 87 of the ProDOS Technical Reference Manual, the paragraph with number 2 states that the name of the system program should be stored in a buffer at $280, starting with a length byte. The first paragraph on page 88 says any non-standard Quit Code must begin with a CLD instruction, so programs can tell who loaded them.
If you want the CLD instruction there, go ahead and insert one between lines 1310 and 1320. I have not found it necessary for any programs I use.
Eric says that when going from BASIC.SYSTEM to APLWORKS.SYSTEM he needed the program name stored in $280. I have never run into the problem, but it is easy to fix. Eric suggested inserting the following two lines:
2065 STA $280 2125 STA $280,Y
[Eric's change takes six bytes, so you need to be sure the code still fits in $300 bytes.]
If you do it Eric's way, only the name of the system file gets stored, without any prefix. I wondered whether or not a full pathname should be there, so I consulted Gary Little's "Apple ProDOS--Advanced Features" book. On page 141, near the bottom, he says either a full or a partial pathname should be put at $280. We can get the full pathname into $280 without Eric's two lines, by simply changing line 4860 from "PATHNAME .BS 64" to "PATHNAME .EQ $280". This is my preference.
When I was trying out the above, I stumbled across a problem. If my Selector finds no SYS or DIR files in a directory, it still displays the pathname and prompt messages. If you then type the RETURN key, it may try to execute garbage, or try various other things. The only valid keystroke when no files are listed is ESCAPE, which will take you back to the list of volume names. Adding two lines makes it go there without displaying the empty list:
1771 TXA see if any files listed 1772 BEQ .2 ...none listed, start over
We noticed the other day that when we ran Erv Edge's correction to my program (Aug 86, page 1), we reversed the information. We said change line 3390 from BNE .1 to BPL .1; actually, it is the other way around: change from BPL to BNE. Most of you figured that out already, but we are sorry for the confusion.
The //gs Monitor has a lot of new features not found in any earlier model Apple. Unfortunately, you do not get any documentation about the monitor with your machine! Next year you will be able to buy a book that will tell you about it, but who wants to wait?
If you go into the monitor and try some of the old commands, you will find that most of them work. Memory display now shows an additional two digits of address, the bank number, and then a slash and the rest of the address. You can enter addresses the same way, so you can display any memory in the entire 16-megabyte range. For example, to disassemble ROM inside the monitor at $FDF0, type "FF/FDF0L". To look at the range of memory in bank FE from 0 to FF, type "FE/0.FF" and a <RETURN>. Note that the disassembler output looks a little different now. There are no dollar signs for hex values, and all opcodes for the 65816 are disassembled. Also note that in memory range display, you get both hex and ASCII values for each byte. If you are in 80-column mode, range display shows 16 bytes per line rather than only 8.
The new monitor preserves almost all the standard entry points, so they are clues to deciphering the rest. Looking at the routines TOSUB (FF/FFBE) and NXTITM (FF/FF73) I found the new addresses for the command character and branch tables. The command characters are in coded form at FF/F98B and following, and the branches are at FF/F9AE and following. There are 35 commands now, a fact learned by the disassembly of NXTITM.
I wrote a program to decipher the contents of these two tables and print the results. It takes a little work, because the characters in the table are not in ASCII. They correspond to ASCII values exclusive-ORed with $B0 and diminished by $89, which takes place inside the GETNUM subroutine (FF/FFA7). The addresses are the low-bytes only of entry points in page $FE of bank $FF (FF/FExx). These addresses must be incremented by one to get the real entry points, because TOSUB uses them by pushing them on the stack and doing an RTS. Anyway, the following program does all the unraveling for you, and prints 35 lines of commands in the order they appear in the tables, showing the entry points for each.
Lines 1110-1170 are an overall loop which runs 35 times, to print the 35 commands. The rest is a subroutine to print one command. By removing the stars from lines 1210-1230, you can get the output in two columns. An advantage to this is that it all fits on one screen.
1000 *Save s.mon.cmd.tbl 1010 *-------------------------------- 1020 COUT .EQ $FDED 1030 PRBYTE .EQ $FDDA 1040 CROUT .EQ $FD8E 1050 *-------------------------------- 1060 LTRS .EQ $F98B Encoded Table of Letters 1070 ADR.LO .EQ $F9AE Command starts at $FExx+1 1080 *-------------------------------- 1090 .OP 65816 1100 *-------------------------------- 1110 PRINT.MONITOR.COMMAND.TABLE 1120 LDY #0 1130 .1 JSR PRINT.ONE.COMMAND 1140 INY 1150 CPY #35 There are 35 commands in table 1160 BCC .1 1170 JMP CROUT 1180 *-------------------------------- 1190 PRINT.ONE.COMMAND 1200 *---REMOVE "***" FOR 2 COLUMNS--------------| 1210 *** TYA CHECK IF ODD OR EVEN | 1220 *** LSR | 1230 *** BCS .0 | 1240 *-------------------------------------------| 1250 JSR CROUT 1260 *---TAB 10 SPACES---------------- 1270 .0 LDX #10 TAB OVER 10 SPACES 1280 LDA #" " 1290 .1 JSR COUT 1300 DEX 1310 BPL .1 1320 *---Convert char to ASCII-------- 1330 LDA LTRS,Y Value from table 1340 SEC 1350 SBC #$89 Reverse process from GETNUM 1360 EOR #$B0 1370 *---Prepare char to print-------- 1380 LDX #" " Space before regular chars 1390 CMP #$A0 1400 BCS .2 ...not control-char 1410 LDX #"^" Caret before control-chars 1420 ORA #$40 Make control-char printable 1430 *---Print the char--------------- 1440 .2 PHA Save char itself 1450 TXA Print Space or Caret 1460 JSR COUT 1470 PLA Print char 1480 JSR COUT 1490 *---Print the address------------ 1500 LDX #3 PRINT " $FE" 1510 .3 LDA FE,X 1520 JSR COUT 1530 DEX 1540 BPL .3 1550 LDA ADR.LO,Y 1560 INC Add 1 because it needs it 1570 JMP PRBYTE 1580 *-------------------------------- 1590 FE .AS -/EF$ / 1600 *-------------------------------- 1610 .LIF |
Seeing all the commands is nice, but it would be easier to read the list if they were in alphabetical order. I modified the program a little, sorted them, and printed them in the order of their ASCII values. Lines 1110-1250 now have two loops. The first one goes through the 35 commands, and stores them into two "sorting trays". I first emptied one of the "trays", by storing zeroes in all 256 locations. Then my SORT.ONE.COMMAND subroutine stores the command ASCII code into the "tray" at the position indexed by the ASCII value itself. The address byte goes into the other "tray" at the same position.
When all 35 commands have been placed into the appropriate positions in the two trays, I run another loop to print out all the non-empty positions. There it is! Simple as can be, they are sorted almost instantaneously.
Then I tried to sort them using the same technique but in the order of the addresses. This did not work, because some addresses are used by more than one command. Only the last command using a particular address printed out. Sigh....
1000 *Save s.moncmds.sort 1010 *-------------------------------- 1020 COUT .EQ $FDED 1030 PRBYTE .EQ $FDDA 1040 CROUT .EQ $FD8E 1050 *-------------------------------- 1060 LTRS .EQ $F98B Encoded Table of Letters 1070 ADR.LO .EQ $F9AE Command starts at $FExx+1 1080 *-------------------------------- 1090 .OP 65816 1100 *-------------------------------- 1110 PRINT.IIGS.MONITOR.COMMANDS.SORTED 1120 JSR CLEAR.SORTING.TRAY.A 1130 LDY #0 1140 .1 JSR SORT.ONE.COMMAND 1150 INY 1160 CPY #35 There are 35 commands in table 1170 BCC .1 1180 *---Print the commands----------- 1190 LDY #0 1200 .2 LDA SORTING.TRAY.A,Y 1210 BEQ .3 1220 JSR PRINT.ONE.COMMAND 1230 .3 INY 1240 BNE .2 1250 JMP CROUT 1260 *-------------------------------- 1270 CLEAR.SORTING.TRAY.A 1280 LDX #0 1290 .1 STZ SORTING.TRAY.A,X 1300 INX 1310 BNE .1 1320 RTS 1330 *-------------------------------- 1340 SORT.ONE.COMMAND 1350 *---Convert char to ASCII-------- 1360 LDA LTRS,Y Value from table 1370 SEC 1380 SBC #$89 Reverse process from GETNUM 1390 EOR #$B0 1400 TAX It is the sorting index 1410 STA SORTING.TRAY.A,X 1420 *-------------------------------- 1430 LDA ADR.LO,Y 1440 INC 1450 STA SORTING.TRAY.B,X 1460 RTS 1470 *-------------------------------- 1480 PRINT.ONE.COMMAND 1490 JSR CROUT 1500 *---TAB 10 SPACES---------------- 1510 LDX #10 TAB OVER 10 SPACES 1520 LDA #" " 1530 .1 JSR COUT 1540 DEX 1550 BPL .1 1560 *---Convert char to ASCII-------- 1570 LDA SORTING.TRAY.A,Y 1580 *---Prepare char to print-------- 1590 LDX #" " Space before regular chars 1600 CMP #$A0 1610 BCS .2 ...not control-char 1620 LDX #"^" Caret before control-chars 1630 ORA #$40 Make control-char printable 1640 *---Print the char--------------- 1650 .2 PHA Save char itself 1660 TXA Print Space or Caret 1670 JSR COUT 1680 PLA Print char 1690 JSR COUT 1700 *---Print the address------------ 1710 LDX #3 PRINT " $FE" 1720 .3 LDA FE,X 1730 JSR COUT 1740 DEX 1750 BPL .3 1760 LDA SORTING.TRAY.B,Y 1770 JMP PRBYTE 1780 *-------------------------------- 1790 FE .AS -/EF$ / 1800 *-------------------------------- 1810 SORTING.TRAY.A .BS 256 1820 SORTING.TRAY.B .BS 256 1830 *-------------------------------- |
David Johnson just called to point out a couple of corrections to his program that converts hi-res graphic images to double hi-res. First, we somehow managed to lose a line of his code. You need to add this line:
2435 LSR XLATE.MONO.AUX,X
Another spot to change is line 2120. The LDA #$03 should really be a LDA #$02, since 3 specifies a full color image and 2 specifies black and white. David reports that 3 has always worked OK for him, so this may not make a real difference, but the specification (ProDOS Technical Note #13) calls for a 2.
An error also crept into the text. Near the end of the fourth paragraph the article says that the AUXMEM portion of the picture is copied into main memory at $4000-5FFF. What the program really does is copy main memory from $2000-3FFF to $4000-5FFF, and then transfer the AUXMEM segment into main memory at $2000-3FFF.
The //gs Toolbox is chock full of useful tools, and no doubt you have heard about a lot of them by now. However, all of the books and articles I have found so far just describe the tools, without showing any actual addresses or tool numbers so they can be called. Most frustrating!
If you remember the article last month about reading and writing the battery RAM in the //gs, you will remember the general way all tools are called. You must be in full-16 native mode, set up the stack in just the right way, put a tool code in the X-register, and do a JSL $E10000.
The tool code is made up of two bytes. The low-order byte is the tool set number, and the high-order byte is the tool number in that tool set. One of the missing items of information in most documentation I have seen so far is the list of tool set numbers. As near as I can figure it all out at this time, the following numbers seem to be established:
Set # Tool ------- -------------------------------- $01 Tool Locater itself $02 Memory Manager $03 Miscellaneous Tools $04 Graphics Core (QuickDraw?) $05 Desk Manager $06 Event Manager $07 Scheduler $08 Sound Manager (Ensoniq stuff) $09 Front Desk Bus $0A SANE (Fancy Floating Point stuff) $0B Integer Math $0C Text Tools $0D <<<I don't know>>> $0E-$20 Various RAM-based tools
The first eight tools in every tools set are all the same, and do not seem to be too important to the casual user. They include boot initialization code, version and status information, reset, and so on. Even a couple of spares.
Of interest to this article, tool number $2A in set $0B will convert a two-byte value to a four-character ASCII string. For example, $12AF would be converted to the four bytes $31, $32, $41, $46. These are the ASCII values for the four hexadecimal digits of $12AF. Lines 1090-1170 in the following program use this tool. Note that all inputs and outputs for the tool are handled through the stack.
Tool $20 of tool set $0C will print out a string in ASCIIZ format. ASCIIZ is a new term to me, which I discovered this week in the Microsoft book "Advanced MS-DOS". It means a string of ASCII characters terminated by a 00 byte. After lines 1140-1170 have placed the ASCII form of the number we converted into the four bytes at HEX (line 1290), we have an ASCIIZ string starting at MSG (lines 1280-1300). Pushing the address of MSG onto the stack and calling for tool $200C will print out the string on the screen. See lines 1180-1220.
Line 1190 may need a word of explanation. The tool needs a four-byte address on the stack, so line 1190 pushes the high-order two bytes of the address. I could have used "PEA MSG/65536", but I like "PEA MSG/256/256" better.
If you have a //gs, try out this little example. It will get you started in understanding all the new tools you have in your toolbox. If you don't have a //gs yet, start saving your nickels!
1000 *SAVE S.PRINT.DEMO 1010 *-------------------------------- 1020 .OP 65816 1030 T 1040 clc GO INTO NATIVE MODE 1050 xce 1060 rep #$30 FULL 16 1070 lda ##$1234 SAMPLE VALUE IN A-REG 1080 *---Tool: convert hex to string------- 1090 PEA 0 4-BYTES FOR RESULT 1100 PEA 0 1110 PHA VALUE TO BE CONVERTED 1120 LDX ##$2A0B TOOL: HEX-VALUE TO ASCII 1130 JSL $E10000 1140 PLA TWO CHARS 1150 STA HEX INTO STRING 1160 PLA TWO MORE CHARS 1170 STA HEX+2 INTO STRING 1180 *---Tool: print a string-------------- 1190 PEA MSG/256/256 1200 PEA MSG ADDRESS OF STRING 1210 LDX ##$200C TOOL: PRINT STRING 1220 JSL $E10000 1230 *-------------------------------- 1240 SEC RETURN IN EMULATION MODE 1250 XCE 1260 RTS 1270 *-------------------------------- 1280 MSG .AS "THE NUMBER IN THE A-REGISTER IS $" 1290 HEX .BS 4 1300 .HS 0D.00 1310 *------------------------------- 1320 .LIF |
In the October or November issue of the Washington Apple Pi newsletter, Rick Chapman wrote a review of various methods of calculating the hi-res base addresses. Steve Wozniak liked the article, and responded with a long "letter to the editor" in the December issue. Steve also presented a new version of the hi-res address calculator which is both shorter and faster. In fact, as far as I am aware, it is the fastest method ever, except for table-lookups.
In the September 1983 issue of Apple Assembly Line, I presented both the original Woz code and a shorter-faster version by Harry Cheung of Nigeria. Here are the specs:
Applesoft ROM version: 33 bytes, 61 cycles Harry Cheung version: 25 bytes, 46 cycles New Wozniak version: 26 bytes, 36 or 37 cycles
The byte counts do not include an RTS at the end of the code, nor do the times include a JSR-RTS. After all, if you are really working for speed you will put the code in its place, not make it a subroutine.
Woz's new version takes either 36 or 37 cycles, depending on the values for the first two bits of the line number. Remember that the line number can be any value from 0 to 191, or $00...$BF. That means the first two bits are either 00, 01, or 10. If you look at lines 1090-1120 below, you will see that the shortest path is for 00, taking both branches, giving a running time for the whole calculation of 36 cycles. If the first two bits are 01 or 10, one branch will be taken and the other not, making the total time 37 cycles. In Woz's letter he shortchanged himself, thinking possibly both branches might not be taken, giving a total running time of 38 cycles; this cannot happen with legal line numbers.
Line 1180 adds in either $10 or $20, depending on which hi-res page you are using. The Applesoft code here adds in a value of either $20 or $40, so if this version were to be inserted into Applesoft the generation of HPAG2 would have to be changed. No problem, and not likely anyway. By the way, if you are only using one specific hi-res page, you can change line 1180 to an immediate mode form, saving yet another cycle.
Here is Woz's new version, reformatted for the S-C Assembler and with some changes in comments:
1000 *SAVE S.NEW.WOZ.HIRES.CALC 1010 *-------------------------------- 1020 GBASL .EQ $26 1030 GBASH .EQ $27 1040 HPAG2 .EQ $E6 Applesoft puts it here anyway. 1050 *-------------------------------- 1060 CALC ASL A--BCDEFGH0 1070 TAX TAX...TXA could be TAY...TYA 1080 AND #$F0 A--BCDE0000 1090 BPL .1 B=0 1100 ORA #$05 A--BCDE0B0B 1110 .1 BCC .2 A-0 1120 ORA #$0A A--BCDEABAB 1130 .2 ASL B--CDEABAB0 1140 ASL C--DEABAB00 1150 STA GBASL 1160 TXA C--BCDEFGH0 1170 AND #$0E C--0000FGH0 1180 ADC HPAG2 O--OOxxFGH0 1190 * HPAG2 = $10 for base $2000, $20 for base $4000 1200 ASL GBASL D--00xxFGHC GBASL=EABAB000 1210 ROL 0--0xxFGHCD 1220 STA GBASH 1230 RTS 1240 *-------------------------------- |
[ Not in printed edition of the newsletter, as far as I can find. However, it was on the Monthly Disk, so I am including it here. ]
1000 *SAVE S.WOZNIAK 1010 *-------------------------------- 1020 * A Number Game for the 6502, by Steve Wozniak 1030 * Published in Dr. Dobb's Journal, September 1976. 1040 *-------------------------------- 1050 * Adapted for the Apple II by Bob Sander-Cederlof 1060 *-------------------------------- 1070 KEYBOARD .EQ $C000 1080 STROBE .EQ $C010 1090 *-------------------------------- 1100 MON.RDKEY .EQ $FD0C 1110 MON.PRBYTE .EQ $FDDA 1120 MON.CROUT .EQ $FD8E 1130 MON.COUT .EQ $FDED 1140 *-------------------------------- 1150 TRIES .EQ $00 1160 RND2L .EQ $03 1170 N .EQ $04 ...08 1180 GUESS .EQ $09 ...0D 1190 *-------------------------------- 1200 RNDL .EQ $4E 1210 RNDH .EQ $4F 1220 *-------------------------------- 1230 T 1240 MSTMND 1250 LDX #Q.RDY Print "READY?" 1260 MSGLP LDA MSG-1,X 1270 JSR MON.COUT 1280 DEX 1290 BNE MSGLP 1300 *---Clear TRY count-------------- 1310 STX TRIES X = 0 1320 *---Wait until player ready------ 1330 * Creates random number in RNDH,RNDL 1340 JSR MON.RDKEY 1350 cmp #$8D Stop if <RETURN> 1360 bne NXTRY 1370 rts 1380 *---Count the try---------------- 1390 * (X-reg is 0 now) 1400 NXTRY SEC 1410 SED 1420 TXA X=0 1430 ADC TRIES Add 1 to tries in BCD mode 1440 STA TRIES 1450 CLD 1460 *---Display the try count-------- 1470 NXTLIN JSR MON.CROUT 1480 LDA TRIES Print number of tries in BCD 1490 JSR MON.PRBYTE 1500 LDA #" " BLANK 1510 TAY $A0, bits 43210 all clear 1520 JSR MON.COUT Print the space 1530 *---Build array of digits-------- 1540 LDA RNDL Use the random number 1550 STA RND2L without changing it 1560 LDA RNDH x5554443 11122233 1570 * (Remember that Y-reg holds $A0) 1580 LDX #5 Do 5 digits 1590 .1 STY N-1,X Be sure bits 43210 are clear 1600 LDY #3 Shift in next three bits from RND 1610 .2 LSR 1620 ROL RND2L 1630 ROL N-1,X 1640 DEY 1650 BNE .2 Next bit 1660 DEX 1670 BNE .1 Next digit 1680 *---Read player's guess---------- 1690 * X- and Y-regs are 0 now 1700 JSR GET.GUESS 1710 BCC NXTLIN 1720 *---Check digits in position----- 1730 * (X-reg is -5 now) 1740 LDY #-5 1750 LDA #" " Print a space 1760 .4 JSR MON.COUT (or a "+") 1770 .5 LDA GUESS+5,X 1780 CMP N+5,X 1790 BNE .6 ...not an exact match 1800 STY N+5,X ...matches, so clobber it 1810 LDA #"+" and print a "+" 1820 STA GUESS+5,X (clobber here too) 1830 INY Count the + 1840 BNE .4 ...not 5 yet, try another 1850 LDX #Q.WIN All 5 correct! 1860 BNE MSGLP Say so, invite another game. 1870 .6 INX Next digit position 1880 BNE .5 1890 *---Check for digits out of position--- 1900 LDY #-5 For each digit in guess... 1910 .7 LDX GUESS+5,Y (Cannot use LDA GUESS+5,Y 1920 TXA because that would not wrap!) 1930 LDX #-5 For each digit in puzzle... 1940 .8 CMP N+5,X 1950 BNE .9 ...different 1960 STY N+5,X ...same, clobber in puzzle 1970 LDA #"-" and print a "-" 1980 JSR MON.COUT 1990 .9 INX Next puzzle digit 2000 BNE .8 2010 INY Next guess digit 2020 BNE .7 2030 BEQ NXTRY ...always, and X must = 0 2040 *-------------------------------- 2050 MSG .AS -/?YDAER/ 2060 .HS 8D 2070 .HS 8D 2080 Q.RDY .EQ *-MSG 2090 .AS -/NIW UOY +/ 2100 Q.WIN .EQ *-MSG 2110 *-------------------------------- 2120 GET.GUESS 2130 .1 LDA KEYBOARD Read char from keyboard 2140 BPL .1 2150 STA STROBE Clear the strobe 2160 CMP #"8" <My little secret!> 2170 BNE .2 2180 LDA N+4,X <Cheat!> 2190 ORA #"0" 2200 .2 JSR MON.COUT Echo the character 2210 EOR #"0" Convert to binary if 0-7 2220 CMP #8 2230 BCS .3 ...Not digit, start try over 2240 STA GUESS+4,X Valid, save the guessed digit 2250 DEX 2260 CPX #-5 2270 BNE .1 Input next digit 2280 RTS 2290 .3 CLC 2300 RTS 2310 *-------------------------------- |
[ Not in printed edition of the newsletter, as far as I can find. However, it was on the Monthly Disk, so I am including it here. ]
I recently received a request for information about the format options in DISASM, the intelligent dis-assembler. Since the format of the generated source code is essentially table-driven, it is rather straightforward to customize the format to match the requirements of different assemblers. The formats for three popular assemblers is built-in, but you could make slight changes to accommodate other assemblers.
The following chart identifies each output parameter, showing its location (in version 2.2e of DISASM), length, and default value. Most of the parameters have three entries, corresponding to the three built-in formats: DOS Toolkit, S-C, and Lisa.
Location Len Name Default Description $0EA5 1 LABELCHR $AE (period) Character after label prefix character. $1309 35 MENUTBL DOS TOOLKIT 8D.00 Info for menu. S-C ASSEMBLER 8D.00 (00 ends item, LISA 8D.00.00 extra 00 ends list) $1326 3 PREFIX IZX First letter for labels: Internal, Zeropage, and eXternal. $1331 3 COMMENT **; Comment character. $1334 3 FIRSTCHR 00.89.00 First character of each line (00 means omit). $1337 6 TABCHR A0.89.A0 Opcode field tab char. A0.A0.A0 Operand field tab char. $133D 3 OPCHR C1.00.00 Operand for implied Accum-mode instruction. $1340 9 PGZEQU EQU.EQEPX Opcode for page-zero definitions. $1349 9 EXTEQU EQU.EQEQU Opcode for other defs. $1352 9 HEXCHR DFB.HSHEX Opcode for hex data. $135B 9 ORGVHR ORG.ORORG Opcode for origin. $1364 9 PRECHR Preamble (start of file). AA.00.00 DOS TK Preamble. 00.00.00 S-C preamble (none). INS Lisa preamble. $136D 3 POSTCHR 00.98.85 Postamble (last char in file).
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 $14 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 CORPORATION,
all rights reserved. (Apple is a registered trademark of Apple Computer, Inc.)