MACHINE CODE PROGRAMMING EXAMPLE page 1 Have you ever looked at a doc file and discovered it was an ASCII file instead of PETASCII. "NEW UTILITY" has a word-processor in it that would convert it to a PETASCII, but some files are too long to fit, so here is a program to convert them. First, here is what the program had to do: (1) Discard any linefeeds. This is a hex $0a or a decimal 10 code. (2) Convert any values beginning at $41 (decimal 65) and ending with $5a (decimal 90) to corresponding values in the range $c1 to $da. This simply involved setting the high bit of the orginal value. These values represent uppercase characters. (3) Convert values in the $61 to $7a range to the corresponding values in the $41 to $5a range. This is accomplished by subtracting $20 from the orginal value.These values represent the lower case letters. To accomplish these objectives, the program combines a combination of BASIC and machine language. BASIC is used to open the file and check for disk errors and machine language to do the converting and write it back to disk. The file is converted as it is read rather than have 2 files open to the disk (it can be done if you want) The converted file is stored in a buffer beginning at $2000 (decimal 8192). When the initial file has been converted, the program returns to BASIC to check for disk errors, close the file, open the write file, check for a good open, and then sys back to the machine language routine to write the file to disk. A sequential file can never contain a hex $00, so that is used to mark the end of the file in the buffer. When that marker is reached, the program returns to BASIC to check for errors and close the file. It's all straigt-forward and a beginner may be able to follow the program well enough to get some understanding of machine language programming. Beginning at line 10, here is an explanation of the listing: Line 10 thru 13 initializes a pointer located in zero page to the address for the beginning of the buffer. Line 14 and 15 set up file #8 as our input file. Line 16 is the beginning of the main loop of this module. It gets a byte from the disk drive. Line 17 and 18 handle the line feeds contained in the ASCII file. If these are left in the converted file then the printout will be double spaced. A "CMP" op-code can give 3 possible results which are: (1) BCC - less-than (the carry is clear) (2) BEQ - equal to (the zero flag is set) (3) BCS - equal-to or greater-than (the carry-flag is set). Lines 19 through 22 will trap all the codes in the $41 to $5a range. In line 20, the branch will occur if the value is LESS-THAN a $41. In line 22 the branch will occur if the value is MACHINE CODE PROGRAMMING EXAMPLE page 2 GREATER-THAN a hex $5a. The comparison is actually made to a hex $5b because the carry is set if the values are equal. Line 23 sets the high bit of the orginal value and line 24 will always branch because no value can be zero with the high bit set. Line 25 through 28 traps the values in the range of $61 to $7a. Lines 29 through 30 convert the values by subtracting a hex $20 from the orginal value. When the SBC opcode is used, it must be preceded with the SEC opcode unless the status of the carry flag is already known. Lines 30 through 34 handle storing the converted value to the buffer. The Y Register is set to zero in line 10 and it has not been changed to this point. The value is actually stored at the address pointed to at aux ($8b) PLUS the value of the Y register. So the first time through the loop, aux contains the address $2000 in standard lo-byte - hi-byte format ($00 $20) and Y is 0, so the first byte is stored at $2000. The second time around the loop, the value is stored at $2001 because y is now 1. Y will be incremented up to 255 ($FF) and at that point the value will be stored at $20FF. When Y is incremented the new value will be 0 and this sets the zero flag tested by the BNE op-code, and since it is "NOT EQUAL TO ZERO" then this branch will not occur and then aux+1 is incremented. Aux will now contain a pointer to the address $2100. This is how the converted values are stored in the buffer and this process will continue as long as the main loop continues. Lines 35 to 38 check for the EOF and terminate the loop when it is detected. The EOF is indicated by the sixth bit of the status byte being set. When you AND the status byte with $40 (binary 0100 0000) the only two possible results are 0 and $40. Our branch here occurs if the result is zero (in other words, the sixth bit was NOT set). Lines 38 and 39 put the eof marker in the buffer. Line 40 restores the input and output devices to normal (input keyboard - output screen). Line 41 will return us to BASIC. The file has now been read from the disk, converting it to PETASCII, and storing it to the temporary buffer. Line 42 is the beginning of the ML code for use when BASIC SYS's back to write the converted file to disk. Line 42 through 45 initialize the zero page pointer to point to the address of $2000 (beginning of the temporary buffer). Line 46 and 47 set up the disk file 8 as the output channel. Line 48 initialized the Y Register to the value of zero. Line 49 is the beginning of the main loop for the write module. It gets a byte from the temporary buffer. MACHINE CODE PROGRAMMING EXAMPLE page 3 Line 50 tests for the EOF marker and branches if detected. Line 51 outputs the byte to the output channel (disk drive in this case). Lines 52 to 55 take care of managing the Y Register and the zero page pointer. This works the same as in lines 32 through 34. Line 56 restores the normal input and output channels and line 57 returns to BASIC. We only get here by detecting the EOF marker back in line 50. The finished code is located in the cassette buffer at decimal 828. The object code is only 98 bytes long. The cassette buffer can hold up to 192 bytes. This code is special in that it is "relocatable", ie., it can run at any address with out being modified. Once the machine code was written and tested, then it was converted it to data statements and added it to the BASIC program. This was done with a program called "make data lines" and then the data file generated was appended to the BASIC file with Tiny Aid. The completed file was re-numbered with Tiny Aid to give it a finishing touch. A side by side listing of the Machine Language portion follows. Hope you enjoy this and let me know if you have any questions. <<<<<...GAIL...>>>>> LISTING FROM MERLIN ASSEMBLER Program by Gail Cox 1 AUX = $8B 2 READST = $FFB7 3 CHKIN = $FFC6 4 CHKOUT = $FFC9 5 CLRCHN = $FFCC 6 CHROUT = $FFD2 7 GETIN = $FFE4 8 * 9 ORG 828 033C: A0 00 10 START LDY #$00 033E: 84 8B 11 STY AUX 0340: A9 20 12 LDA #$20 0342: 85 8C 13 STA AUX+1 0344: A2 08 14 LDX #$08 0346: 20 C6 FF 15 JSR CHKIN 0349: 20 E4 FF 16 MAIN JSR GETIN 034C: C9 0A 17 CMP #$0A ;no linefeed 034E: F0 F9 18 BEQ MAIN 0350: C9 41 19 CMP #'a' ;$41 0352: 90 13 20 BCC OK MACHINE CODE PROGRAMMING EXAMPLE page 4 0354: C9 5B 21 CMP #'z'+1 ;$7b 0356: B0 04 22 BCS CKMOR 0358: 09 80 23 ORA #$80 035A: D0 0B 24 BNE OK 035C: C9 61 25 CKMOR CMP #'A' ;$61 035E: 90 07 26 BCC OK 0360: C9 7B 27 CMP #'Z'+1 ;$7b 0362: B0 03 28 BCS OK 0364: 38 29 SEC 0365: E9 20 30 SBC #$20 0367: 91 8B 31 OK STA (AUX),Y 0369: C8 32 INY 036A: D0 02 33 BNE CKST 036C: E6 8C 34 INC AUX+1 036E: 20 B7 FF 35 CKST JSR READST 0371: 29 40 36 AND #$40 0373: F0 D4 37 BEQ MAIN 0375: A9 00 38 LDA #$00 0377: 91 8B 39 STA (AUX),Y 0379: 20 CC FF 40 JSR CLRCHN 037C: 60 41 RTS 037D: A9 00 42 WRITE LDA #$00 037F: 85 8B 43 STA AUX 0381: A9 20 44 LDA #$20 0383: 85 8C 45 STA AUX+1 0385: A2 08 46 ...
Amiga7878