PETASCII To ASCII Conversion
Brian Niessen
Chemainus, B.C.
This very useful machine language routine is well worth its weight in gold when it comes to using your PET/CBM wth ASCII devices such as MODEMS and printers. It's short length (56 bytes) and ease of use make it very easy to add to any existing programs. The assembler listing included is for BASIC 3.0 ROM's. The changes needed for BASIC 2.0 ROM's and BASIC 4.0 ROM's are listed below.
For BASIC 2.0, change COMMA to $CE11 from $CDF8, change EVAL to $CCB8 from $CC9F, and change PTR to $96 from $44. For BASIC 4.0, change COMMA to $BEF5 from $CDF8 and change EVAL to $BD98 from $CC9F. The PTR location is the same for BASIC 4.0 as it is for BASIC 3.0, as Commodore promised it would be.
The machine language program works as follows. It is invoked with a SYS(NNN),A$ statement. The (NNN) is the first location of the ML routine and the string variable A$ is the string to be converted. The ML program then jumps to the routine COMMA, which checks for – you guessed it – the comma which seperates the SYS(NNN) and the A$. The next jump is to a subroutine called EVAL which looks at the variable A$ and puts its location in PTR and PTR + 1.
CBM/PET identifies characters somewhat differently than the industry standard, the ASCII code. In ASCII, the number 65 means uppercase "A," as it does to PET BASIC. However, if you POKE 32768,65, the screen will either display a spade or lowercase "a," depending on whether you are in "text" or "graphics" mode at the time. Everything is kept straight for you by BASIC, but when you try to communicate with a device outside the computer (a MODEM or a printer), some adjustments may need to be made. This is why wordprocessors like WordPro always first ask you to indicate whether you are using a Commodore printer, an ASCII printer, etc. Mr. Niessen's machine language program does the translating. It takes the CBM/PET character codes and modifies them to conform to ASCII. Within the article, he provides the necessary changes to make the program work on all CBM models: Original (2.0), Upgrade (3.0), and BASIC (4.0). |
By using an indirect indexed addressing mode, you can get the length of the string by loading the Y register with zero and executing a LDA(PTR), Y. The length of the string is then transferred into the accumulator and saved into location STRLEN. Next, the Y register is incremented so it has a value of one, and another LDA(PTR), Y is executed. This time the LO byte of the beginning of the actual string in memory is returned. This is saved in the location STRLO. Again the Y register is incremented and the LDA(PTR),Y instruction is executed again, returning the HI byte of the location of the string, which is saved in STRHI.
Now knowing the location and length of the string to be converted, the routine can convert it from PETASCII to ASCII on a character by character basis, beginning with the last one and working forward. It uses the following algorithm:
IF(A) > = 65 AND (A) < = 90 THEN (A) = (A) OR 32 ELSE I (A) > = 193 AND (A) < = 219 THEN (A) = (A) AND 127
Characters above $7B have no ASCII equivalent and are left as is.
The subroutine then returns to BASIC, with the contents of the string A$ converted to ASCII. The string can now be printed normally.
One thing to remember is that the original contents of the string are changed. If the string were dynamically declared, as in the following example, it will be changed within the program:
10 A$ = "STRING" : SYS(NNN), A$
because the PET, to save memory space, sets the pointers to the actual string in the program. Instead use:
10 A$ = "STRING" + " " : SYS(NNN), A$
which will cause the string to be stored away in high memory.
I hope this will prove as useful to others as it has been to me. It was tested on the EPSON MX-80 printer.
References:
Commodore User's Reference Manual—PN 321604
Page E-1, Paragraph I
The PET Revealed
Nick Hampshire, Computabits Ltd, P.O. Box 13, Yeovil, Somerset, England
PET/CBM Personal Computer Guide
Adam Osborne-Carroll S. Donahue
Osborne/McGraw-Hill
LINE# LOC CODE LINE 0001 0000 ; *************************************** 0002 0000 ; * PETASCII TO ASCII SUBROUTINE * 0003 0000 ; * BY: BRIAN NIESSEN. * 0004 0000 ; * * 0005 0000 ; * BOX 571 * 0006 0000 ; * CHEMAINUS, B.C. VOR 1KO * 0007 0000 ; * (604) 246-4556 * 0008 0000 ; *************************************** 0009 0000 ; *TO USE: SYS(NNN), A$ * 0010 0000 ; *WHERE (NNN) IS START LOCATION * 0011 0000 ; *A$ IS STRING TO BE CONVERTED * 0012 0000 ; *************************************** 0013 0000 ; LOCATIONS FOR 2001 (BASIC 3.0) 0014 0000 COMMA = $CDF8 0015 0000 EVAL = $CC9F 0016 0000 STRLO = $DA 0017 0000 STRHI = $DB 0018 0000 STRLEN = $F9 0019 0000 PTR = $44 ;POINTER USED IN EVAL ROUTINE 0020 0000 * =634 ;STARTING LOCATION FOR ROUTINE 0021 027A 20 F8 CD JSR COMMH ;CHECK FOR COMMA 0022 027D 20 9F CC JSR EVAL ;EVALUATE EXPRESSION 0023 0280 A0 00 LDY #0 ;SAVE STRING LOCATION 0024 0282 B1 44 LDA (PTR), Y 0025 0284 85 F9 STA STRLEN 0026 0286 C8 INY 0027 0287 B1 44 LDA (PTR), Y 0028 0289 85 DA STA STRLO 0029 028B C8 INY 0030 028C B1 44 LDA (PTR), Y 0031 028E 85 DB STA STRHI 0032 0290 ;PROCESS STRING ONE CHARACTER AT A TIME. 0033 0290 A4 F9 LDY STRLEN ;GET STRING LENGTH 0034 0292 B1 DA LOOP LDA (STRLO), Y 0035 0294 C9 41 CMP #$41 ;IF $41<=A<$5A THEN A=A OR $20 0036 0296 90 12 BCC DONE ;IF 'A <=A<= 'Z THEN A=A OR 32 0037 0298 C9 5B CMP #$5B 0038 029A B0 04 BCS SECOND 0039 029C 09 20 ORA #$20 0040 029E D0 0A BNE DONE ;JUMP ALWAYS 0041 02A0 SECOND ;FIRST FAILED-TRY SECOND 0042 02A0 C9 C1 CMP #$C1 ;IF $C1<=A<=$DA THEN A=A AND $7F 0043 02A2 90 06 BCC DONE 0044 02A4 C9 DB CMP #$DB 0045 02A6 B0 02 BCS DONE 0046 02A8 29 7F AND #$7F 0047 02AA 91 DA DONE STA (STRLO), Y 0048 02AC 88 DEY 0049 02AD C0 FF CPY #$FF 0050 02AF D0 E1 BNE LOOP 0051 02B1 0052 02B1 60 RTS ;RETURN TO BASIC 0053 02B2 .END