In This Issue...
More on ProDOS and Nonstandard Apples
In the March issue we published Bob Stout's note on how to make ProDOS boot in a Franklin computer. The current issue, (No. 9) of Hardcore Computist points out that the address given in that note didn't work for the ProDOS version dated 1-JAN-84. Apparently Bob was referring to an earlier version. The correct address for the NOPs is $265B.
In a similar vein, inside this issue Jan Eugenides points out that ProDOS will also fail in an Apple with a modified Monitor ROM. He then gives a slightly different patch to defeat the check code.
Feedback on installment one of this series came from as far away as Sweden. Paul Schlyter, with others, pointed out the omission of three very important letters. PRINT (14.9*10) indeed prints 149, as expected. What I meant to say was that PRINT INT(14.9*10) prints 148.
I noticed another error at the top of page 21. The exponent range runs from 10^-63 thru 10^63, not 10^64.
Paul pointed out that my routines did not check for underflow and overflow. I did have such checks in another part of the code, as yet unlisted, but I now agree with him that some checks belong in the routines printed last month.
The subroutine SHIFT.DAC.RIGHT.ONE is called when a carry beyond the most significant bit is detected in DADD, at line 1620. If the exponent is already 10^63, or $7F, this shift right will cause overflow. That means the sum formed by DADD is greater than 10^63, and we need to do either of two things. My usual choice, assuming the routines are being used from Applesoft, is to JMP directly to the Applesoft ROM overflow error routine, at $E8D5. Another option is to set the DAC exponent to $7F, and the mantissa to all 9's. To implement it my way, add these lines:
1945 BMI .2 2085 .2 JMP $E8D5
Underflow needs to be tested in the NORMALIZE.DAC subroutine. Underflow happens when the exponent falls below 10^-63. The normal procedure upon underflow is to set the result to zero. Zero values in DP18 are indicated by the exponent being zero, regardless of the mantissa value. Delete lines 2400-2480 and line 2730, and enter the following lines
2400 LDY #-1 2410 .1 INY 2420 CPY #10 2430 BCS .7 2440 LDA DAC.HI,Y 2450 BEQ .1 2730 .6 LDA DAC.EXPONENT 2731 BPL .8 2732 .7 LDA #0 2733 STA DAC.EXPONENT 2734 STA DAC.SIGN 2735 .8 RTS
All these changes will be installed on Quarterly Disk 15.
This month I want to present several pack and unpack subroutines, and one which rounds the value in DAC according to the value in the extension byte.
Note that I have just LISTed the subroutines below, rather than showing the assembly listing, because the program parts need to all be assembled together before they are meaningful.
There are two "unpack" subroutines, MOVE.YA.DAC and MOVE.YA.ARG. They perform the "load accumulator" function. There is one "pack" subroutine, MOVE.DAC.YA, which performs the "store accumulator" function.
The MOVE routines use a page-zero pair at $5E and $5F. Assuming the DP18 package will be called from Applesoft via the &-vector, there will be no page-zero conflicts here.
The subroutines DADD and DSUB from last month, and DMULT and DDIV to come, all expect two arguments in DAC and ARG and leave the result in DAC. Assuming there are two packed DP18 value at VAL.A and VAL.B, and that I want to add them together and store the result in VAL.C, I would do it this way:
LDA #VAL.A LDY /VAL.A JSR MOVE.YA.DAC LDA #VAL.B LDY /VAL.B JSR MOVE.YA.ARG JSR DADD LDA #VAL.C LDY /VAL.C JSR MOVE.DAC.YA
Note that MOVE.DAC.YA calls ROUND.DAC before storing the result. ROUND.DAC checks the extension byte. If the extension byte has a value less than $50, no rounding need be done. If it is $50 through $99, the value in DAC should be rounded up. If the higher digits are less than .999999999999999999, then there will be no carry beyond the most significant digit, and no chance for overflow. However, if it is all 9's we will get a final carry and we will need to change the number to 100000000000000000 and add one to the exponent. In tiny precision, this is like rounding .995 up to 1.00. If the exponent was already 10^63, rounding up with a final carry causes overflow, so I jump to the Applesoft error handler.
1000 *SAVE S.DP18 PACK & UNPACK 1010 *------------------------------- 1020 * ADDRESSES INSIDE APPLESOFT 1030 *------------------------------- 1040 AS.OVRFLW .EQ $E8D5 OVERFLOW ERROR 1050 *-------------------------------- 1060 * PAGE ZERO USAGE 1070 *------------------------------- 1080 PNTR .EQ $5E,5F 1090 *------------------------------- 1100 * MOVE (Y,A) INTO DAC AND UNPACK 1110 *-------------------------------- 1120 MOVE.YA.DAC 1130 STA PNTR 1140 STY PNTR+1 1150 LDY #9 MOVE 10 BYTES 1160 .1 LDA (PNTR),Y 1170 STA DAC,Y 1180 DEY 1190 BPL .1 1200 INY Y=0 1210 STY DAC.EXTENSION 1220 LDA DAC.EXPONENT 1230 STA DAC.SIGN 1240 AND #$7F 1250 STA DAC.EXPONENT 1260 RTS 1270 *-------------------------------- 1280 * MOVE (Y,A) INTO ARG AND UNPACK 1290 *-------------------------------- 1300 MOVE.YA.ARG 1310 STA PNTR 1320 STY PNTR+1 1330 LDY #9 MOVE 10 BYTES 1340 .1 LDA (PNTR),Y 1350 STA ARG,Y 1360 DEY 1370 BPL .1 1380 INY Y=0 1390 STY ARG.EXTENSION 1400 LDA ARG.EXPONENT 1410 STA ARG.SIGN 1420 AND #$7F 1430 STA ARG.EXPONENT 1440 RTS 1450 *-------------------------------- 1460 * PACK AND MOVE DAC TO (Y,A) 1470 *-------------------------------- 1480 MOVE.DAC.YA 1490 STA PNTR 1500 STY PNTR+1 1510 JSR ROUND.DAC 1520 LDA DAC.EXPONENT 1530 BIT DAC.SIGN 1540 BPL .1 POSITIVE 1550 ORA #$80 NEGATIVE 1560 .1 LDY #0 1570 .2 STA (PNTR),Y 1580 INY 1590 LDA DAC,Y 1600 CPY #10 1610 BCC .2 1620 RTS 1630 *-------------------------------- 1640 * ROUND DAC BY EXTENSION 1650 *-------------------------------- 1660 ROUND.DAC 1670 LDA DAC.EXTENSION 1680 CMP #$50 COMPARE TO .5 1690 BCC .3 NO NEED TO ROUND 1700 LDY #8 1710 SED DECIMAL MODE 1720 .1 LDA #0 1730 ADC DAC.HI,Y 1740 STA DAC.HI,Y 1750 BCC .2 NO NEED FOR FURTHER PROPAGATION 1760 DEY 1770 BPL .1 ...MORE BYTES 1780 INC DAC.EXPONENT 1790 BMI .4 ...OVERFLOW 1800 LDA #$10 .999...9 ROUNDED TO 1.000...0 1810 STA DAC.HI 1820 .2 CLD 1830 .3 LDA #0 1840 STA DAC.EXTENSION 1850 RTS 1860 .4 CLD 1870 JMP AS.OVRFLW 1880 *-------------------------------- |
None of the pack/unpack code is especially tricky, but the same cannot be said for DMULT. Multiplication is handled "just like you do it with pencil and paper", but making it happen at all efficiently makes things look very tricky.
Call DMULT after loading the multiplier and multiplicand into DAC and ARG (doesn't matter which is which, because multiplication is commutative). Then JSR DMULT to perform the multiply. The result will be left in DAC.
Looking at the DMULT code, lines 1040-1070 handle the special cases of either argument being 0. Anything times zero is zero, and zero values are indicated by the exponent being zero, so this is real easy.
Lines 1090-1130 clear a temporary register which is 20 bytes long. This register will be used to accumulate the partial products. Just in case some of the terminology is losing you, here are some definitions:
12345 <-- multiplicand x 54321 <-- multiplier --------- 12345 <-- 1st partial product 24690 <-- 2nd partial product 37035 <-- 3rd " " 49380 <-- 4th " " 61725 <-- 5th " " --------- 670592745 <-- product
Lines 1150-1180 form the 20-digit product of the two 10-digit arguments. I wanted to reduce the number of times the individual digits have to be isolated, or the accumulators shifted by 4-bits, so I used a trick. Line 1150 calls a subroutine which multiplies the multiplicand (in ARG) by all the low-order digits in each byte of the multiplier (in DAC). In other words, I accumulate only the odd partial products at this time. Then I shift DAC 4-bits right, which places the other set of digits in the low-order side of each byte. I also have to shift the result register, MAC, right 4-bits, and then I call the MULTIPLY.BY.LOW.DIGITS subroutine again.
Lines 1200-1270 form the new exponent, which is the sum of the exponents of the two arguments. Since both exponents have the value $40 added to make them appear positive, one of the $40's has to be subtracted back out. But before that, if the sum is above $C0 then we have an overflow condition. After subtracting out one of the $40's, if the result is negative we have an underflow condition. Note that since the carry status was clear at line 1250, I subtracted $3F; for one more byte, I could have done it the normal way and used SEC, SBC #$40.
Lines 1290-1310 form the sign of the product, which is the exclusive-or of the signs of the two arguments. Lines 1330-1370 copy the most significant 10 bytes of the product from MAC to DAC.
The result may have a leading zero digit in the left half of the first byte, so I call NORMALIZE.DAC at line 1390. If The leading digit was zero, normalizing will shift DAC left one digit position, leaving room for another significant digit on the right end. Lines 1400-1490 handle installing the extra digit if necessary.
MULTIPLY.BY.LOW.DIGITS picks up the low-order digit out of each byte of the multiplier, one-by-one, and calls MULTIPLY.ARG.BY.N.
MULTIPLY.ARG.BY.N does the nitty-gritty multiplication. And here is where I lost all my ingenuity, too. The multiplier digit is stored in DIGIT, and used to count down a loop which adds ARG to MAC DIGIT times. Surely this can be done more efficiently! How about it Paul? Or Charlie? Anyone?
1000 *SAVE S.DP18 MULTIPLY 1010 *-------------------------------- 1020 * DAC = ARG * DAC 1030 *-------------------------------- 1040 DMULT LDA DAC.EXPONENT IF DAC=0, EXIT 1050 BEQ .3 1060 LDA ARG.EXPONENT IF ARG=0, SET DAC=0 AND EXIT 1070 BEQ .4 1080 *---CLEAR RESULT REGISTER-------- 1090 LDA #0 1100 LDY #19 1110 .1 STA MAC,Y 1120 DEY 1130 BPL .1 1140 *---FORM PRODUCT OF FRACTIONS---- 1150 JSR MULTIPLY.BY.LOW.DIGITS 1160 JSR SHIFT.MAC.RIGHT.ONE 1170 JSR SHIFT.DAC.RIGHT.ONE 1180 JSR MULTIPLY.BY.LOW.DIGITS 1190 *---ADD THE EXPONENTS------------ 1200 LDA DAC.EXPONENT 1210 CLC 1220 ADC ARG.EXPONENT 1230 CMP #$C0 CHECK FOR OVERFLOW 1240 BCS .5 ...OVERFLOW 1250 SBC #$3F ADJUST OFFSET 1260 BMI .4 ...UNDERFLOW 1270 STA DAC.EXPONENT 1280 *---FORM SIGN OF PRODUCT--------- 1290 LDA DAC.SIGN 1300 EOR ARG.SIGN 1310 STA DAC.SIGN 1320 *---MOVE MAC TO DAC-------------- 1330 LDY #9 1340 .2 LDA MAC,Y 1350 STA DAC.HI,Y 1360 DEY 1370 BPL .2 1380 *---NORMALIZE DAC---------------- 1390 JSR NORMALIZE.DAC 1400 LDA MAC IF LEADING DIGIT=0, 1410 AND #$F0 THEN GET ANOTHER DIGIT 1420 BNE .3 1430 LDA MAC+10 1440 LSR 1450 LSR 1460 LSR 1470 LSR 1480 ORA DAC.HI+9 1490 STA DAC.HI+9 1500 .3 RTS 1510 .4 LDA #0 1520 STA DAC.SIGN 1530 STA DAC.EXPONENT 1540 RTS 1550 .5 JMP AS.OVRFLW 1560 *-------------------------------- 1570 * MULTIPLY BY EVERY OTHER DIGIT 1580 *-------------------------------- 1590 MULTIPLY.BY.LOW.DIGITS 1600 SED DECIMAL MODE 1610 LDX #9 1620 LDY #19 1630 .1 LDA DAC.HI,X 1640 AND #$0F ISOLATE NYBBLE 1650 BEQ .2 0, SO NEXT DIGIT 1660 JSR MULTIPLY.ARG.BY.N 1670 .2 DEY NEXT MAC POSITION 1680 DEX NEXT DAC DIGIT 1690 BPL .1 DO NEXT DIGIT 1700 CLD BINARY MODE 1710 RTS DONE 1720 *-------------------------------- 1730 MULTIPLY.ARG.BY.N 1740 STA DIGIT N = 1...9 1750 STY TEMP SAVE Y 1760 STX TEMP+1 SAVE X 1770 .1 LDX #9 INDEX INTO ARG 1780 CLC 1790 .2 LDA ARG.HI,X 1800 ADC MAC,Y ADD IT 1810 STA MAC,Y 1820 DEY NEXT MAC 1830 DEX NEXT ARG 1840 BPL .2 NEXT DIGIT 1850 BCC .4 NO CARRY 1860 .3 LDA #0 PROPAGATE CARRY 1870 ADC MAC,Y 1880 STA MAC,Y 1890 DEY 1900 BCS .3 MORE CARRY 1910 .4 LDY TEMP GET POSITION IN MAC 1920 .5 DEC DIGIT NEXT DIGIT 1930 BNE .1 1940 LDX TEMP+1 1950 RTS DONE 1960 *-------------------------------- 1970 SHIFT.MAC.RIGHT.ONE 1980 LDY #4 4 BITS RIGHT 1990 .0 LDX #1 20 BYTES 2000 LSR MAC 2010 .1 ROR MAC,X 2020 INX NEXT BYTE 2030 PHP 2040 CPX #20 2050 BCS .2 NO MORE BYTES 2060 PLP 2070 JMP .1 2080 .2 PLP 2090 DEY NEXT BIT 2100 BNE .0 2110 RTS 2120 *-------------------------------- |
Well, that's all for this month. Next month expect some simple I/O routines and the divide subroutine.
The other day I was thinking about the way Apple spells ProDOS. They jealously guard the spelling, having trademarked the idea of upper-case "P" and "DOS" with lower-case "ro".
Of course, we all know that "Pro" is a standard prefix, with origins in the Greek language. In Greek it means "before". I think Apple derived it from the English word "professional", so that ProDOS means "professional DOS". Nevertheless, the "pro" even in the word professional means before, according to the etymologies in dictionaries.
I took some Greek courses at Dallas Theological Seminary back in 1973 and 1974. I remember very little now, but one thing stuck with me: prepositions. "Pro" is one, but there are a lot more. What other interesting DOSses can we invent?
By the way, the preferred pronunciation of DOS rhymes with "boss", not "gross". If you insist on rhyming with the latter, your pronunciation has a decided Spanish accent. For you we have invented "UnoDOS", which is of course two-thirds of a popular product on the IBM-PC, uno-dos-tres by Lotus. Ha!
The first that came to mind was "ParaDOS". We like it so well, we've decided to trademark it! It could relate to either paradox or pair-of-dice or paradise, take your pick. A shrewdly written DOS could appear as all three at different times to different people.
Bill and I then started to brainstorm, and we can't stop. We've got a blackboard full of neat names, just waiting for some one to write code for. We may have stumbled on to some previously-used names, like SoliDOS and ProntoDOS, but for the most part I think we have cornered the market.
AmbiDOS MisoDOS PhiloDOS BiblioDOS ViviDOS DiaDOS PaleoDOS MesoDOS NeoDOS PsychoDOS MoriDOS Dial-a-DOS ChromoDOS BlancoDOS TechniDOS SomatoDOS DulciDOS AnoDOS AcriDOS FeloniDOS BaloniDOS FormiDOS MiniDOS CathoDOS MicroDOS MidiDOS MilliDOS MegaDOS NanoDOS VagaDOS TeraDOS UniDOS BioDOS StupiDOS TorriDOS FabriDOS SemiDOS PeriDOS AntiDOS AnteDOS ProsDOS ExoDOS HypoDOS HyperDOS OvaDOS PupaDOS PropoDOS EnDOS ArcheDOS StatiDOS DynamoDOS DynaDOS ProtoDOS EschatoDOS OsteoDOS MultiDOS PuroDOS CardioDOS PyroDOS PrimaDOS FrigiDOS InterDOS AndroDOS GynoDOS GymnoDOS PseudoDOS HieroDOS SpiroDOS HelioDOS CycloDOS AutoDOS AggreDOS ManoDOS ChiroDOS PetroDOS LithoDOS AeroDOS PosiDOS PlanoDOS LiquiDOS MarbleDOS PedoDOS GraviDOS NegaDOS PedaDOS GeriaDOS NutriDOS FlexiDOS PleniDOS NecroDOS VisiDOS InvisiDOS FluoriDOS FloriDOS FaunaDOS PensaDOS ThanaDOS AgriDOS NaviDOS NovaDOS SpuriDOS MensaDOS StereoDOS VerbiDOS VermiDOS CineDOS GeoDOS TragiDOS MonoDOS DuoDOS CobraDOS FerroDOS OxyDOS AfroDOS EuroDOS NippoDOS FrancoDOS IndoDOS CanaDOS HispanoDOS
Get the idea?
I have packed even more goodies on eight disk sides, combining the HACKER and USER packages into one powerful Toolkit. The price is only slightly higher... They were $29.50 each, now only $39.50 together.
Now that we have yet another Apple monitor, vastly different yet purportedly compatible, guess what! Applewriter //e is not QUITE compatible with the //c. Surprise, surprise! The status line display gets turned into garbage. One of the patches included in the new AWIIe Toolkit solves the problem admirably. This AWIIE CLARIFIER Applesloth program modifies your Applewriter IIe backup diskettes to eliminate trashing of the IIc status display line. Here it is now, more than slightly compressed for AAL, to tease you into getting the whole Toolkit:
100 REM *---------------------------------------* 200 REM * COPYRIGHT 1984 BY DON LANCASTER AND * 220 REM * SYNERGETICS, BOX 1300, THATCHER AZ * 240 REM * 85552 Phone: (602) 428-4073 * 260 REM * ALL COMMERCIAL RIGHTS RESERVED * 280 REM *---------------------------------------* 380 TEXT : HOME : HIMEM: 8000 400 HTAB 8: PRINT "Applewriter IIe CLARifier": PRINT 600 REM Check Validity 660 PRINT CHR$(4)"BLOAD OBJ.APWRT][F,A$2300 670 IF PEEK (14815) < > 188 THEN 880 680 IF PEEK (15052) < > 41 THEN 880 690 IF PEEK (15096) < > 59 THEN 880 695 REM Install Patches 700 POKE 14815,60: POKE 14816,36: POKE 14817,207: POKE 14818,16: POKE 14819,2: POKE 14820,169: POKE 14821,62 710 POKE 15052,208: POKE 15053,42 720 POKE 15062,96 730 POKE 15096,41: POKE 15097,127: POKE 15098,201: POKE 15099,96: POKE 15100,176: POKE 15101,208: POKE 15102,201: POKE 15103,64 740 POKE 15104,144: POKE 15105,204: POKE 15106,41: POKE 15107,63: POKE 15108,176: POKE 15109,200 750 PRINT CHR$(4)"UNLOCK OBJ.APWRT][F" 760 PRINT CHR$(4)"BSAVE OBJ.APWRT][F,A$2300,L$30D3" 770 PRINT CHR$(4)"LOCK OBJ.APWRT][F" 870 PRINT "IT WORKED!" : END 880 PRINT "Will not verify as AWIIe; patch ABORTED" : END
Gotchas: Fixes only the status line. Rare and brief changes in the flashing cursor symbol will remain.
New users of the S-C Macro Assembler have asked for examples of how to use some of the customizing features. For example, just now I had a call from a gentleman who needed to know how to set up the PRT vector to turn on his printer and send the special control strings it requires.
It happens that I had the same problem just a few weeks ago. I just picked up an OkiData 92 printer, which I am quite happy with, except for a couple of small warts. Setting Elite spacing (12 characters/inch, 8 lines/inch) on that printer requires these hex codes: 9C 9B B8. The catch is that 9C, which corresponds to Control-backslash. I can't type CTRL-\ on my Apple II+! Besides, by the time I type in the commands to turn on the printer, set Elite mode, and set a left margin, I have entered 15 keystrokes. That's too many for my lazy, dyslexic fingers, so I came up with a PRT command to do the whole job.
The addresses in this routine are set up for the 40-column Version 1.1 Language Card assembler. If you are using another version, check to make sure that the patch space is indeed all zeroes. All $D000 versions of the assembler have some blank space before $E000. If you are using a $1000 version, look to see if there is some space available between the end of the assembler and the beginning of the Symbol Table and set PATCH.SPACE to that address. You will also have to set PRT.VECTOR to $1009.
Here are the exact steps to use this patch:
Start the assembler. $C083 C083 $D01C:0 D0 0 F8 $AA60.AA61 LOAD S.PRT ASM $D01C:0 0 0 0 $C080 BSAVE <assembler>,A$D000,L$XXXX
The $AA60.AA61 line gives you the length that you will need to use for the BSAVE command. Substitute the filename of the version you use for <assembler> in the above command.
If you are using Version 1.0 of the assembler, things are a little different. You should omit the $D01C entries in the above commands, delete lines 1090 and 1100, and add this line to the program:
1125 .TA $800
Then, after the assembly, install the patch with $DF00<800.81EM and $D009: 4C 00 DF. These extra steps are necessary because Version 1.0 lacks the ability to override memory protection during assembly.
Lines 1270-1290 are where you should install the codes your printer needs.
1000 *-------------------------------- 1010 * 1020 * SAMPLE PRT COMMAND 1030 * 1040 *-------------------------------- 1050 PRT.VECTOR .EQ $D009 1060 PATCH.SPACE .EQ $DF00 1070 MON.COUT .EQ $FDED 1080 *-------------------------------- 1090 .OR PRT.VECTOR 1100 JMP PRT JUMP TO HANDLER 1110 *-------------------------------- 1120 .OR PATCH.SPACE 1130 1140 PRT LDX #0 1150 .1 LDA STRING,X OUTPUT THE 1160 BEQ .2 CONTROL 1170 JSR MON.COUT STRING 1180 INX 1190 BPL .1 1200 1210 .2 RTS 1220 *-------------------------------- 1230 STRING .HS 8D84 <CR><^D> 1240 .AS -/PR#1/ 1250 .HS 8D <CR> 1260 1270 .HS 9C9BB8 ELITE SPACING 1280 .HS 9BA5C3 LEFT MARGIN 1290 .HS B0B9B0 90 DOT SPACES 1300 .HS 00 END MARKER |
Remember all those warnings about storing 0 in $48 after DOS had a whack at your zero page? Maybe not, but let me remind you.
Apple's monitor uses locations $45 through $49 in a very special way. Ignoring this, the writers of DOS also used them. When you start execution from the monitor (using the G, S, or T commands) The data in these locations gets loaded into the registers: $45 into A, $46 into X, $47 into Y, $48 into P (status), and $49 into S (stack pointer). When a program hits a BRK opcode, or the S command has finished executing a single opcode, the monitor saves these five registers back into $45...$49.
No serious problem, unless you like to enter the monitor and issue the G, S, or T commands. Even less of a problem, because the S and T commands were removed from the monitor ROM when the Apple II Plus came out. And if you don't care what is in the registers anyway....
But the P-register is rather special, too. One of its bits, called "D", controls how arithmetic is performed. If "D" is zero, arithmetic will be done in the normal binary way; if D=1, arithmetic is done in BCD mode. That is, adding one to $49 will produce $50 rather than $4A. If the program you are entering doesn't expect to be in decimal mode, and tries arithmetic, you will get some rather amusing results.
Hence the warning: before using the G command from the monitor, type 48:0 to be sure decimal mode is off. Later versions of DOS store 0 into $48 after calling those routines which use $48. And the monitor stores 0 into $48 whenever you hit the RESET key (or Control-RESET).
****************************************************** * * * Now I am here to tell you that storing 0 into * * $48 is ALL WRONG! It took Bill and me 5 hours * * to unravel the mystery caused by storing zero * * there! * * * ******************************************************
You should put into $48 a sensible value. Better, DOS should never use $45 through $48; if it must use them, save and restore them. There are eight bits in the P-register, and in the 6502 seven of them are important. One of them, we discovered, is VERY important.
The bit named "I" controls the IRQ interrupt. If I=1, IRQ interrupts will not be accepted. If I=0, IRQ interrupts will be accepted. So...who cares about interrupts?
Hardly anyone uses interrupts in Apple II's, because of all the hidden problems. But there are some very nice boards for the Apple that are designed to be used with interrupts. Most of them are safe, because RESET disables their interrupt generators.
Need I say that we discovered a board that does not disable the interrupt generators when you hit RESET? The Novation Cat Modem (a very excellent product) leaves at least one of its potential IRQ sources in an indeterminate state. IRQ's don't immediately show up, though, because they are trapped until you have addressed any of the soft switches on the card. But, for example, if that card is in slot 2 and I read or write any location from $C0A0 through $C0AF, IRQ's start coming. Still no problem, because I=1 in the P-register.
UNTIL WE USE THE MONITOR G COMMAND!
If I use the monitor G command, location $48, containing 0, is loaded into the P-register. Then an IRQ gets through and sends the 6502 vectoring through an unprepared vector at $3FE,3FF and BANG!
Our solution was to put SEI instructions in various routines, and to make sure that $48 contains 4, not 0, before using the G command.
From now on, whenever you hear that you need to be sure $48 contains zero, think four.
I published my "Random Numbers for Applesoft" article last month just in time. The June issue of Micro includes a 9.5 page article called "A Better Random Number Generator", by H. Cem Kaner and John R. Vokey. The article reports on work funded by the Natural Sciences and Engineering Research Council of Canada (NSERC).
The authors give an excellent overview of the various methods used to test random number generators, and the methods they used during their seven years of research to produce three "better" generators. It is worth buying a copy of Micro to get a copy of this article.
The authors used the same linear congruential algorithm I discussed last month, but with different parameters. My favorite last month was:
R(new) = ( R(old) * A + C ) mod 2^32 where A = 314159269 and C = 907633386
Kaner and Vokey decided to use a 40-bit seed and use mod 2^40 in calculating each successive value. After extensive analysis and testing, they came up with three generators based on the following values for "A" and "C":
RNG 1: A = 31415938565 C = 26407 RNG 2: A = 8413453205 C = 99991 RNG 3: A = 27182819621 C = 3
There are an unusually large number of typos in the article, and some of them are hard to decipher. The value 26407 above was written in the comment field as 24607; however, in the hexadecimal constant assembly code it was 0000006727, which is 26407. Even worse, in the listing there are missing lines of code and missing characters here and there. All of the immediate mode instructions are missing a "#" character. Four or five labels are never defined in the listing.
Since the program as printed cannot possibly be successfully loaded, assembled, POKEd, or executed, I have chosen to re-write it for inclusion here, after my own style. I believe my version is also significantly improved in coding and speed.
The reason given for choosing to work with 40 bits rather than 32, even though Applesoft only stores 32 and using 40 takes longer, was that it is important to provide more values between 0.0 and 2^-32. I tend to disagree on the importance of this, since most uses of random numbers on the Apple are for games, and simulate such simple things as dealing cards or throwing dice. Perhaps more serious simulations need more precise randomness. Of course they also increase by a factor of 256 the number of numbers generated before the sequence repeats.
Buried in the middle of the program is a well-optimized 40-bit multiplication loop. You might enjoy puzzling out how it works!
The program uses USR(x), where x selects which of the three generators to use. There is no provision for setting the seed or for selecting a range other than 0...1, such as I included in my programs last month. Some enterprising individual will marry the shell of my USR subroutine with the RNG of Kaner and Vokey to produce a really great Applesoft Random Number Generator.
1 .LIF 1000 *SAVE S.KANER & VOKEY 1010 *-------------------------------- 1020 * BASED ON PROGRAM PRINTED IN MICRO MAGAZINE 1030 * JUNE 1984, PAGES 33,34, BY H. CEM KANER 1040 * AND JOHN R. VOKEY 1050 *-------------------------------- 1060 USER.VECTOR .EQ $0A,0B,0C 1070 FAC .EQ $9D THRU $A1 1080 FAC.SIGN .EQ $A2 1090 FAC.EXT .EQ $AC 1100 *-------------------------------- 1110 NORMALIZE.FAC.2 .EQ $E82E 1120 *-------------------------------- 1130 .OR $300 1140 .TF B.KANER & VOKEY 1150 *-------------------------------- 1160 LINK LDA #$4C "JMP" OPCODE 1170 STA USER.VECTOR 1180 LDA #RANDOM 1190 STA USER.VECTOR+1 1200 LDA /RANDOM 1210 STA USER.VECTOR+2 1220 RTS 1230 *-------------------------------- 1240 Z.C .HS 00.00.00.67.27 26407 1250 Z.A .HS 07.50.89.2E.05 31415938565 1260 Z.OLD .HS 00.00.00.00.00 1270 *-------------------------------- 1280 Y.C .HS 00.00.01.86.97 99991 1290 Y.A .HS 01.F5.7B.1B.95 8413453205 1300 Y.OLD .HS 00.00.00.00.00 1310 *-------------------------------- 1320 X.C .HS 00.00.00.00.03 3 1330 X.A .HS 06.54.38.E9.25 27182819621 1340 X.OLD .HS 00.00.00.00.00 1350 *-------------------------------- 1360 GROUP .BS 1 1370 MULTIPLIER .BS 5 1380 OLD .BS 5 1390 *-------------------------------- 1400 RANDOM LDY #Z.C-Z.C+4 1410 LDA FAC.SIGN 1420 BMI .1 SELECT Z 1430 LDY #Y.C-Z.C+4 1440 LDA FAC 1450 BEQ .1 SELECT Y 1460 LDY #X.C-Z.C+4 SELECT X 1470 .1 STY GROUP SAVE FOR LATER 1480 *---LOAD SELECTED GROUP---------- 1490 LDX #4 MOVE 5 BYTES 1500 .2 LDA Z.C,Y 1510 STA FAC+1,X 1520 LDA Z.A,Y 1530 STA MULTIPLIER,X 1540 LDA Z.OLD,Y 1550 STA OLD,X 1560 DEY 1570 DEX 1580 BPL .2 1590 *---MULTIPLY INTO FAC------------ 1600 LDX #4 1610 .3 STX FAC.EXT USE FOR BYTE COUNT 1620 LDA MULTIPLIER,X 1630 STA FAC SAVE FOR 8-BIT MULITPLY 1640 LDY #7 COUNT BITS 1650 .4 LSR FAC GET RIGHTMOST BIT INTO CARRY 1660 BCC .6 =0, SO WE DO NOT ADD THIS TIME 1670 CLC =1, SO WE BETTER ADD 1680 .5 LDA FAC+1,X 1690 ADC OLD,X 1700 STA FAC+1,X 1710 DEX 1720 BPL .5 1730 .6 ASL OLD+4 SHIFT MULTIPLICAND LEFT 1740 ROL OLD+3 1750 ROL OLD+2 1760 ROL OLD+1 1770 ROL OLD 1780 LDX FAC.EXT GET BYTE COUNT AGAIN 1790 DEY NEXT BIT 1800 BPL .4 1810 DEX REDUCE BYTE COUNT 1820 BPL .3 ...MORE BYTES 1830 *---SAVE NEW SEED IN OLD--------- 1840 LDX #4 1850 LDY GROUP 1860 .7 LDA FAC+1,X 1870 STA Z.OLD,Y 1880 DEY 1890 DEX 1900 BPL .7 1910 *---NORMALIZE NEW VALUE---------- 1920 LDY #$80 ASSUME A FRACTION 1930 .8 LDA FAC+1 LOOK AT LEADING BIT 1940 BMI .9 ...FINISHED NORMALIZING 1950 LSR FAC.SIGN 1960 ROR FAC+4 1970 ROR FAC+3 1980 ROR FAC+2 1990 ROR FAC+1 2000 DEY 2010 CPY #$58 2020 BCS .8 2030 LDY #0 LESS THAN 2^-40 IS ZERO 2040 .9 STY FAC EXPONENT 2050 LDA #0 2060 STA FAC.SIGN MAKE IT POSITIVE 2070 RTS |
You may have already figured this out, but ProDOS won't boot if you have installed S. Knouse's modified ROM in your Apple. This can easily be fixed, as follows:
Ta daaa! Now ProDOS works just fine with your modified ROM.
In the April 1984 Call-APPLE there was a letter from John Wallace regarding a problem with the Andromeda 16K RAM card. As this card was the second on the market, first after Apple's (which was bundled with Pascal), there are probably still tens of thousands in use. Yet the Andromeda is anathema to some hardware and software.
In particular, it played havoc with John Wallace's copy of Apple PIE (a popular word processor from yesteryear), and my Lobo 8" floppy drive controller (another relic, I suppose). Bob S-C tells of running into the problem too:
"I have an Andromeda board, and I ran into this problem with early versions of ES-CAPE. Using a STA (or other store) opcode to any soft switches on the Andromeda card write-protected the card. Using two stores in a row to try to write-enable the card does no good either. I had to change all stores to loads or BITs to make it work. Apple's board accepts either stores or loads, as do all other memory cards I have tested."
There are probably lots of interfaces and programs out there which stumble over Andromeda. Wallace details a hardware modification to the Andromeda board which makes it work the same as all other memory boards. I found a slightly simpler way, and I recommend that all Andromeda owners fix their boards as soon as possible.
Remove the 74LS08 chip at board location U13. Bend pin 10 out so that it sticks straight out, and plug the chip back into its socket so that pin 10 is on the outside. Solder a small wire to pin 10 (carefully), and solder the other end of the wire to pin 14 of the same chip. Or, you can solder to a solder pad pin 14 is connected to, as shown in the drawing below. (Pin 14 is connected to Vcc, the +5 volts line.) That's all there is to it.
John Wallace suggests using a 1K resistor rather than a wire, but I found a wire is sufficient.
With the wire installed, both reads and writes can be used to switch the card, just like Apple intended it.
The April 1984 AAL article about using Cyclic Redundancy Codes posed the question, "How do you find out which bit was in error, assuming only one was wrong?" I found a way.
My algorithm assumes that there was one and only one bit wrong in the entire 258-byte message (256 bytes of original message plus 2 bytes of CRC). The bits are numbered left-to-right, or most significant bit of first byte received through the least significant bit of the CRC, 0 through $80F (or 2063, if you prefer decimal).
After receiving the data and CRC, the RECV program has computed a composite CRC and the result will be $0000 if there were no errors. If the result is non-zero, it uniquely determines which bit was wrong. Here is a summary of my algorithm for finding which bit:
let bit.number = 2063 let dummy.crc = 1 -->if dummy.crc = crc, then we found the bit | decrement bit.number | shift dummy.crc left 1 bit | if carry set, EOR with $1021 ---loop
[ The following comments are by Bob Sander-Cederlof. ]
The program listing which follows is an addendum to the listing in the April issue of AAL. Lines 3070 through the end should be appended to the program in that issue. If you buy the AAL Quarterly Disk, it will already be there.
The sequence I used for testing the program went like this. First I assembled the whole program, April's plus the one below. Then I typed "$4000<F800.F8FFM" to move a copy of the monitor's first page into the test buffer. I thought this would be "interesting" data to play with. Then these steps:
:MGO SEND (fakes sending the buffer) 1F45 (SEND prints out the CRC for BUFFER) :$4000 (see what is there) 4A (it was $4A) :$4000:CA (make a fake error in the 1st bit) :MGO RECV xxxx (some non-zero value) :MGO FIND.BAD.BIT 0000 (the bad bit was the first bit) $4000:4A (restore the correct bit
Then I tried the same steps on various other bit positions, with accurate results in every case.
1000 *SAVE S.CRC BAD BIT FINDER 1010 *-------------------------------- 1020 BUFFER .EQ $4000 1030 LIMIT .EQ $4102 1040 *-------------------------------- 1050 CRC .EQ $00,01 1060 PNTR .EQ $02,03 1070 TPTR .EQ $04,05 1080 TMASK .EQ $06 1090 SPTR .EQ $07,08 1100 SMASK .EQ $09 1110 *-------------------------------- 1120 PRNTAX .EQ $F941 1130 CROUT .EQ $FD8E 1140 PRBYTE .EQ $FDDA 1150 COUT .EQ $FDED 1160 *-------------------------------- 3060 *-------------------------------- 3070 * FIND WHICH BIT IS BAD IN BUFFER+CRC 3080 * 3090 * RESULT IS BIT POSITION IN MESSAGE, 3100 * WHERE THE FIRST BIT OF THE MESSAGE IS BIT 0 3110 * AND (IN THIS CASE) THE LAST CRC BIT IS BIT $80F. 3120 * 3130 * ALGORITHM BY BRUCE LOVE, AUSTRIALIA. 3140 *-------------------------------- 3150 BIT.NUMBER .EQ $10,11 3160 DUMMY.CRC .EQ $12,13 3170 *-------------------------------- 3180 FIND.BAD.BIT 3190 LDA #$80F TOTAL # BITS - 1 3200 STA BIT.NUMBER (WE WILL COUNT BACKWARDS) 3210 LDA /$80F 3220 STA BIT.NUMBER+1 3230 LDA #$0001 STARTING POINT FOR BIT FINDER 3240 STA DUMMY.CRC 3250 LDA /$0001 3260 STA DUMMY.CRC+1 3270 .1 LDA CRC COMPARE RECEIVED CRC WITH 3280 CMP DUMMY.CRC PROCESSED VALUE; 3290 BNE .2 IF THEY MATCH, WE HAVE FOUND THE 3300 LDA CRC+1 BAD BIT. 3310 CMP DUMMY.CRC+1 3320 BEQ .4 ...FOUND BAD BIT! 3330 .2 LDA BIT.NUMBER DECREMENT BIT COUNTER 3340 BNE .3 3350 DEC BIT.NUMBER+1 3360 BMI .5 WENT TOO FAR 3370 .3 DEC BIT.NUMBER 3380 ASL DUMMY.CRC 3390 ROL DUMMY.CRC+1 3400 BCC .1 3410 LDA DUMMY.CRC 3420 EOR #$21 3430 STA DUMMY.CRC 3440 LDA DUMMY.CRC+1 3450 EOR #$10 3460 STA DUMMY.CRC+1 3470 JMP .1 3480 .4 LDA BIT.NUMBER+1 PRINT THE BIT NUMBER 3490 JSR PRBYTE (IF $8000, THE ERROR WAS 3500 LDA BIT.NUMBER NOT A SINGLE BIT) 3510 JSR PRBYTE 3520 JMP CROUT 3530 .5 BRK 3540 *-------------------------------- |
Did you notice Dave Barkovitch's ad last month? He has written a very handy set of utilities for us serious Applers, and sells 'em cheap! Be prepared to puzzle your way through his admittedly skimpy documentation, but it is all there.
The I/O Tracer comes in EPROM on a little card that plugs into any slot 1-7 for only $40.50 (including shipping). I/O Tracer is essentially a powerful disk ZAP utility, allowing you to read/write/edit any DOS 3.3 sector. You see an entire sector at once on the screen, in either hex or ASCII, along with all status information.
Dave's Single-Step Trace program will help you debug assembly language. He likes it better than the other commercial varieties of debuggers, and sells it for only $35.
Any questions, call Dave at (201) 499-0636.
Last April I told how to convert object code to the Intellec Hex Format (AAL pages 14-18, April, 1984). Both Intel and Zilog use that format. Motorola, on the other hand, has its own format for object code. It is similar, but it is significantly different. If you are programming for a Motorola chip, or using a PROM burner that uses Motorola format, then the following program is for you.
The Motorola S-Type format has three kinds of records: header, data, and end-of-file. Each record begins with the letter "S" and ends with a carriage return linefeed (CRLF). According to the samples I have seen, all of the bytes in a record are in ASCII code with the high bit zero. (Apple peripherals tend to like the high bit = 1, so I made this an option.) The maximum length including the "S" and up to but not including the CRLF is 64 "frames". Between the "S" and CRLF, each record consists of five fields:
Record format field: ASCII 0, 1, or 9 (hex $30, $31, or $39) for header, data, or end-of-file records respectively.
Byte count field: the count expressed as two ASCII digits of the number of bytes (half the number of frames) from address field through the checksum field. The minimum is 3, and the maximum is 60 decimal or $3C hexadecimal.
Address field: four frames representing the four digits of the load address for data bytes in a data record, or the run address in an end-of-file record. All four digits will be "0" in a header record.
Data field: two hex digits for each byte of data. The number of bytes will be 3 less than the number specified in the byte count field, because that count includes two bytes for the address and one byte for the checksum.
Checksum field: two hex digits representing the 1's complement of the binary sum of all the bytes in the previous four fields.
If you compare the S-Type format with the Intellec format, you will note several differences:
I tried to use as much as possible of the Intellec program when writing the Motorola program. You will find a lot of similarities if you compare the two. Both are designed to be used with the monitor's control-Y instruction. Both expect you to enter the output slot number or address in zero-page bytes 0 and 1.
The Motorola program requires two additional pieces of information. It needs a byte at 0002 which will be either $00 or $80, denoting whether to set the high bit to 0 or 1 on every output byte. It also needs an eight character name for the header record. This should be entered in zero-page locations 0003 through 000A.
For example, assume the object code I want to format is in the Apple between $6000 and $67FF. In the target processor it will load at address $1000. The name of the program is "SAMPLE". I want to send the data with the high bit = 0. The device I want to send it to is connected to an intelligent peripheral card in slot 2. Here is what I type:
]BRUN B.MOTOROLA FORMATTER (or :BRUN B.MOTOROLA FORMATTER ]CALL -151 (or :MNTR) *0:2 0 (send to slot 2) *:0 (hi-bit = 0) *:53 41 4D 50 4C 45 20 20 ("SAMPLE") *1000<6000.67FF^Y (^Y means control-Y)
I recommend comparing this program and my description of it with the Intellec program and article in the April AAL. Here is the Motorola formatter:
1000 *SAVE S.MOTOROLA S-TYPE OBJECT 1010 .OR $800 1020 *-------------------------------- 1030 PORT .EQ $00,01 1040 HI.BIT .EQ $02 1050 NAME .EQ $03 ... $0A 1060 CHECK.SUM .EQ $12 1070 TYPE .EQ $13 1080 COUNT .EQ $14 1090 REMAINING .EQ $15,16 1100 START .EQ $17,18 1110 END .EQ $19,1A 1120 TARGET .EQ $1B,1C 1130 *-------------------------------- 1140 A1 .EQ $3C,3D 1150 A2 .EQ $3E,3F 1160 A3 .EQ $40,41 1170 A4 .EQ $42,43 1180 A5 .EQ $44,45 1190 *-------------------------------- 1200 CTRLY.VECTOR .EQ $3F8 THRU $3FA 1210 DOS.REHOOK .EQ $3EA 1220 *-------------------------------- 1230 MON.NXTA4 .EQ $FCB4 1240 MON.CROUT .EQ $FD8E 1250 MON.PRHEX .EQ $FDDA 1260 MON.COUT .EQ $FDED 1270 MON.SETVID .EQ $FE93 1280 *-------------------------------- 1290 * SETUP CONTROL-Y 1300 *-------------------------------- 1310 SETUP LDA #SEND.DATA 1320 STA CTRLY.VECTOR+1 1330 LDA /SEND.DATA 1340 STA CTRLY.VECTOR+2 1350 LDA #$4C 1360 STA CTRLY.VECTOR 1370 RTS 1380 *-------------------------------- 1390 * *0:XX YY (LO,HI OF PORT) 1400 * *:ZZ (00 OR 80, FOR ASCII HI-BIT) 1410 * *:C1 C2 C3 C4 C5 C6 C7 C8 ASCII VALUES FOR 1420 * THE 8 CHARACTERS OF THE NAME 1430 * *TARGET<START.END<Y> 1440 * IF PORT IS 0, DO NOT CHANGE OUTPUT 1450 * IF PORT IS 1...7, OUTPUT TO SLOT. 1460 * ELSE OUTPUT TO SUBROUTINE 1470 * SEND BYTES START...END 1480 * 1490 * 1. TURN ON OUTPUT PORT 1500 * 2. SEND ID RECORD 1510 * 3. SEND DATA RECORDS 1520 * 4. SEND EOF RECORD 1530 * 5. TURN OFF OUTPUT PORT 1540 *-------------------------------- 1550 SEND.DATA 1560 JSR SAVE.PARAMETERS 1570 JSR TURN.ON.OUTPUT.PORT 1580 JSR SEND.ID.RECORD 1590 JSR RESTORE.PARAMETERS 1600 JSR SEND.DATA.RECORDS 1610 JSR SEND.EOF.RECORD 1620 JMP TURN.OFF.OUTPUT.PORT 1630 *-------------------------------- 1640 SAVE.PARAMETERS 1650 LDX #1 1660 .1 LDA A1,X 1670 STA START,X 1680 LDA A2,X 1690 STA END,X 1700 LDA A4,X 1710 STA TARGET,X 1720 DEX 1730 BPL .1 1740 RTS 1750 *-------------------------------- 1760 RESTORE.PARAMETERS 1770 LDX #1 1780 .1 LDA START,X 1790 STA A1,X 1800 LDA END,X 1810 STA A2,X 1820 LDA TARGET,X 1830 STA A4,X 1840 DEX 1850 BPL .1 1860 RTS 1870 *-------------------------------- 1880 TURN.ON.OUTPUT.PORT 1890 LDX PORT+1 HI-BYTE OF PORT SPECIFIED 1900 BNE .1 1910 LDA PORT LO-BYTE, MUST BE SLOT 1920 AND #$07 1930 BEQ .3 SLOT 0, JUST SCREEN 1940 ORA #$C0 1950 BNE .2 ...ALWAYS 1960 .1 TXA HI-BYTE OF SUBROUTINE 1970 LDX PORT LO-BYTE OF SUBROUTINE 1980 .2 STA $37 1990 STX $36 2000 JSR DOS.REHOOK 2010 .3 RTS 2020 *-------------------------------- 2030 SEND.ID.RECORD 2040 LDA #'0' TYPE = "0" 2050 STA TYPE 2060 LDA #8 COUNT = 8 2070 STA COUNT 2080 LDA #0 ADDR=0 2090 STA A4 2100 STA A4+1 2110 STA A1+1 2120 STA A2+1 2130 LDA #NAME 2140 STA A1 2150 LDA #NAME+7 2160 STA A2 2170 JMP SEND.RECORD 2180 *-------------------------------- 2190 SEND.DATA.RECORDS 2200 LDA #'1' TYPE = "1" 2210 STA TYPE 2220 INC A2 POINT JUST BEYOND THE END 2230 BNE .1 2240 INC A2+1 2250 .1 SEC 2260 LDX #20 2270 LDA A2 SEE HOW MANY BYTES LEFT 2280 SBC A1 2290 STA REMAINING 2300 LDA A2+1 2310 SBC A1+1 2320 STA REMAINING+1 2330 BNE .2 USE MIN(20,A2-A1+1) 2340 CPX REMAINING 2350 BCC .2 2360 LDX REMAINING 2370 BEQ .3 ...FINISHED 2380 .2 STX COUNT 2390 JSR SEND.RECORD 2400 JMP .1 ...ALWAYS 2410 .3 RTS 2420 *-------------------------------- 2430 SEND.EOF.RECORD 2440 LDA #0 # OF DATA BYTES = 0 2450 STA COUNT 2460 LDA #'9' TYPE="9" 2470 STA TYPE 2480 LDA TARGET RUN ADDRESS (LO) 2490 STA A4 2500 LDA TARGET+1 RUN ADDRESS (HI) 2510 STA A4+1 2520 JMP SEND.RECORD 2530 *-------------------------------- 2540 TURN.OFF.OUTPUT.PORT 2550 JSR MON.SETVID 2560 JMP DOS.REHOOK 2570 *-------------------------------- 2580 SEND.RECORD 2590 LDA #'S' LETTER "S" 2600 JSR SEND.FRAME 2610 LDA TYPE TYPE "0", "1", OR "9" 2620 JSR SEND.FRAME 2630 LDA #0 INIT CHECKSUM 2640 STA CHECK.SUM 2650 CLC 2660 LDA COUNT SEND BYTE COUNT 2670 ADC #3 ...INCLUDING ADDR AND CSUM 2680 JSR SEND.BYTE 2690 LDA A4+1 SEND ADDRESS 2700 JSR SEND.BYTE 2710 LDA A4 2720 JSR SEND.BYTE 2730 LDA COUNT ANY DATA? 2740 BEQ .2 ...NO 2750 LDY #0 ...YES, SEND DATA 2760 .1 LDA (A1),Y 2770 JSR SEND.BYTE 2780 JSR MON.NXTA4 2790 DEC COUNT 2800 BNE .1 2810 .2 LDA CHECK.SUM SEND CHECK SUM 2820 EOR #$FF 2830 JSR SEND.BYTE 2840 LDA #$0D SEND CRLF 2850 JSR SEND.FRAME 2860 LDA #$0A LINEFEED 2870 JMP SEND.FRAME 2880 *-------------------------------- 2890 SEND.BYTE 2900 PHA SAVE BYTE 2910 CLC 2920 ADC CHECK.SUM ACCUMULATE CHECKSUM 2930 STA CHECK.SUM 2940 PLA RECOVER BYTE 2950 PHA SAVE ANOTHER COPY 2960 LSR READY FIRST DIGIT 2970 LSR 2980 LSR 2990 LSR 3000 JSR SEND.DIGIT 3010 PLA RECOVER BYTE 3020 AND #$0F READY SECOND DIGIT 3030 SEND.DIGIT 3040 ORA #$30 CHANGE TO ASCII 3050 CMP #$3A 3060 BCC SEND.FRAME 3070 ADC #6 CHANGE TO A...F 3080 SEND.FRAME 3090 ORA HI.BIT $00 OR $80 3100 JMP MON.COUT 3110 *-------------------------------- 3120 .OR $300 3130 SAMPLE 3140 .HS 86.44.B7.01.00.41.42.43 3150 .HS 44.45.46.47.48.49.4A.4B 3160 .HS 4C.4D.4E |
I am writing this on my Apple II Plus running a 2 MHz 65C02 (GTE G65SC02PI-2). All is well now, but it took some doing.
A few days after pluggin in the chip I started noticing problems. Applesoft found itself unable to process numeric literals, and the version of FORTH I have been developing began acting weird.
Following the tip in AAL that the timing of the fetch-process- save instructions might be responsible, I ran some tests on them. The 65C02 worked flawlessly. Apparently the problem is elsewhere.
After further checking, especially in my FORTH, I found that a certain BNE instruction sitting in the first byte of a page and branching backward into the prior page frequently branched back one byte less than it should.
I'm not a hardware person, but I figured debugging is debugging and I really wanted that chip to work, so I began staring at the circuit diagram in the Apple Reference manual. After several hours I concluded that I stood for input, O for output, D for data, and A for address.
The easiest hypothesis to check seemed to be that data was not getting back from the RAMs to the microprocessor in time. So I wrote down some chip numbers and went downtown to see if I could buy some faster variants. Well, the first two chips I replaced solved the problem.
They were 74LS257 chips at B6 and B7. These chips multiplex the output of RAM with the output of the keyboard and send the result to the 65C02. I replaced them with 74F257 chips. I understand these consume less power, respond faster, and are more susceptible to electrostatic damage.
Anyway, my 65C02 is happy now. I would like to hear whether this modification works in other Apples, and with other 65C02s. Drop a line to Bob and Bill at S-C if you have any word on this.
Apple Assembly Line is published monthly by S-C SOFTWARE CORPORATION, P.O. Box 280300, Dallas, Texas 75228. Phone (214) 324-2050. Subscription rate is $18 per year in the USA, sent Bulk Mail; add $3 for First Class postage in USA, Canada, and Mexico; add $12 postage for other countries. Back issues are available for $1.80 each (other countries add $1 per back issue for postage).
All material herein is copyrighted by S-C SOFTWARE, all rights reserved.
Unless otherwise indicated, all material herein is authored by Bob Sander-Cederlof.
(Apple is a registered trademark of Apple Computer, Inc.)