Copy Link
Add to Bookmark
Report

Machine Language - Part III

by Lyle Giese

DELPHI Mail: LYLEG


Last month, I showed you how to print to the screen. This month we will print the alphabet to the screen. And next month we will look into disk I/O. Now don't let this scare you away. It is really not that hard. It does take a few steps more than you would need in BASIC, but the increase in speed is well worth it.

To start off here is this month's program. Again I am using the simple assembler put the program in memory.

.A C000 LDA #$01 
.A C002 LDX #$04
.A C004 LDY #$07
.A C006 JSR $FFBA
.A C009 LDA #$00
.A C00B JSR $FFBD
.A C00E JSR $FFC0
.A C011 LDX #$01
.A C013 JSR $FFC9
.A C016 LDY #$41
.A C018 TYA
.A C019 JSR $FFD2
.A C01C INY
.A C01D CPY #$5B
.A C01F BNE $C018
.A C021 LDA #$0D
.A C023 JSR $FFD2
.A C026 JSR $FFCC
.A C029 LDA #$01
.A C02B JSR $FFC3
.A C02E RTS
.A C02F <CR>

Definitely, a little more typing but it is not that hard to figure out. The key to it is learning to read the Kernal information in the Programers Reference Guide. As I have been doing in the previous articles, will be using the 64's PRG.

So we want to send some characters (in this case the alphabet) to the printer. How do we do it in BASIC? We must first issue an OPEN command. And we will do the same in ML.

If you look at page 289 in the PRG, you will find that the Kernal has a routine called OPEN. How do we use it? Lets take a look at the information there.

First it tells us what the routine does, open a logical file. Then it gives us the address we need to call the routine. How we communicate with it is next; but it says none. How do we tell it the secondary address, logical file number, or even the device number?

That is what the next entry cares for. What routines need to be called before this one can be called, Preparatory routines. And that is what I did in my little program above.

So it says we need to call SETLFS first. So let's go there and take a look at it. It tells us to set up a logical file. Its address is $FFBA and we use all three registers to communicate with it. No preparatory routines are needed. It returns no error codes, needs room for 2 entries in the stack, and returns with the A, X, and Y registers intact.

In the description, we find out that the Accumulator is loaded with the logical file number ($01). The X register is loaded with the device number ($04) and the Y register is loaded with the secondary address ($07). Be sure to note the Y register is loaded with $FF (255) if you don't want to send a secondary address. And then we call the routine with the JSR $FFBA at $C006.

Now we need to call the secondary preparatory routine-SETNAM. SETNAM is used to set up the file name for the logical file. When doing I/O to a cassette or disk drive, this is important. But to a printer?? Well we just set the length of the filename to zero. As you read the description of this routine, you will find that we do that by putting a zero in the accumulator. If we did have a filename, the address of it would go into the X (low order byte) and the Y (high order byte) registers. And at $C00B we JSR $FFBD and complete that preparatory routine.

Now we can open out file by a JSR $FFC0. Note that all registers are affected. If you had some information you wanted to save you would have to copy it into a memory location prior to calling this routine and restore it afterwards.

In my example, I did not check the error status after the open. But in a bigger program or if the logical file is a disk or cassette file, you would at this point check for errors in opening the file. You do this by the READST routine. If we didn't and we forgot to hook up the printer to the computer, the alphabet would be sent to the screen.

Now again let's go back to BASIC for a moment. We have opened our logical file to the printer. In BASIC how do we direct our output to the printer? With the CMD#1 command. In ML you have to open an output channel to the device. The routine for this is CHKOUT.

The description for CHKOUT says that we have to use the OPEN routine first, which we have. The X register is the communication register. We put the number of the logical file in it ($01). Make sure you use the logical file and not the device number. And of course note that the Accumulator and X register are changed during the routine.

Now we have the logical file open and the output being directed to the printer. How do we send it? Time for the good old CHROUT routine. And if we read the description of it, it tells us that we must use the CHKOUT and OPEN routines first if we are sending to something other than to the screen, which we have already done.

We load the PETSCII code for the letter "A" into the Accumulator and then call the CHROUT routine and then increase the accumulator and check if we have printed all of the alphabet. And branch back to print if not, right? NO! Absolutely not!

This was the first big mistake I made when I started to program in ML. I did not read or comprehend the entry 'Registers affected: .A' in the description of CHROUT. That means the Accumulator is CHANGED while executing this routine. We have to have some other means of keeping track of the desired value. I decided to use the Y register in this program. So we start out by putting the value of $41 (the letter a) in the Y register and copying that into the Accumulator.

Now we call the CHROUT ($FFD2) routine. Upon exiting we INY (remember it is not affected by CHROUT) and check if it is Z+1 or $5B. If it is not we branch back to the TYA instruction and reload the Accumulator and print it again.

Now after 26 times through the loop, we have sent the entire alphabet to the printer. We fall through the BNE instruction at $C021. We load the value of $0D (a plain old carriage return) and send it out to the printer. Why?

Most (but not all) printers buffer incoming characters until a carriage return or 80 characters are received before printing. So it is a good habit to get into, that of sending a carriage return just before closing the printer's output file.

Now we must tidy things up a bit by restoring the screen as the output device. That routine is called CLRCHN and we call it with a JSR $FFCC. Now we must close the logical file #1. We do that by loading the Accumulator with the logical file number ($01) and then JSR $FFC3 (CLOSE).

And we return to where we were when we called this short routine with the RTS instruction.

One thing I can tell you for sure---this explanation takes a lot longer to read than it takes to execute!

Lyle Giese (Delphi Mail: LYLEG)

← previous
next →
loading
sending ...
New to Neperos ? Sign Up for free
download Neperos App from Google Play
install Neperos as PWA

Let's discover also

Recent Articles

Recent Comments

Neperos cookies
This website uses cookies to store your preferences and improve the service. Cookies authorization will allow me and / or my partners to process personal data such as browsing behaviour.

By pressing OK you agree to the Terms of Service and acknowledge the Privacy Policy

By pressing REJECT you will be able to continue to use Neperos (like read articles or write comments) but some important cookies will not be set. This may affect certain features and functions of the platform.
OK
REJECT