Classic Computer Magazine Archive COMPUTE! ISSUE 89 / OCTOBER 1987 / PAGE 61

INSIGHT: Atari

Bill Wilkinson


Machine Language Graphics: The Final Installment

This month I will finally show you the machine language equivalents of the most important BASIC screen I/O operations. We'll begin with an example. Suppose we wanted to implement a GRAPHICS 7 statement. From two months ago, we know that the equivalent low-level statements are

CLOSE #6
OPEN #6,12 + 16,7,"S:"

A direct translation into machine language follows.

;GRAPHICS 7
;CLOSE IOCB 6
 LDX #$60		; IOCB number
 LDA #12		; the CLOSE command
 STA ICCOM,X		; put in place
 JSR $E456		; call CIO
;OPEN IOCB 6
 LDX #$60		; IOCB number
 LDA #3		; the OPEN command
 STA ICCOM,X		; put in place
 LDA #12 + 16	; give it the same
				; value
 STA ICAX1, X		; as you would in
				; BASIC
 LDA #7
 STA ICAX2, X
 LDA #DEVICE&$FF	; don't worry why
 STA ICBAL, X		; this works
 LDA #DEVICE/$100; it just does.
 STA ICBAL + 1, X
 JSR $E456		; do the real work

Don't bother assembling this code yet—it won't work without some of the help given later in this article.

Now, if you all you ever wanted to do was emulate GRAPHICS 7, that would be an adequate method. But in BASIC, the general form of the command is GRAPHICS mode, where mode is any numeric variable or expression or your choice. It would be better if we could emulate that in machine language. And, to some degree, we can.

In BASIC's GRAPHICS statement, the mode value is called a parameter to the operation. In machine language, we also use parameters. With the 6502 microprocessor that Atari machines use, we usually try to pass the parameters in one or more of the three registers that the chip possesses: the A register (also called the accumulator), the X register, and the Y register. Suppose you need to pass an IOCB number. Since it needs to be in the X register for the call to CIO anyway, why not pass it there?

The listing that follows is not a program in and of itself. Rather it is a set of subroutines that your program may call (via JSR) to implement the given operation. At the very end of the article you will find a sample program that calls these subroutines.

When you use the subroutines in your own programs, you must note carefully the description of the parameters that I have given. Be sure that the appropriate registers contain the proper values before you jump to a subroutine.

The listing is given without line numbers. Some assemblers use line numbers, but, when they do, it's for editing purposes only—the numbers have no effect on the program. Comments are preceded by a semicolon. You may omit any of them that you like. When you have typed all this in (and have checked it carefully for errors—one mistake can cause a lockup), you should save it (or LIST it, depending upon your assembler) to disk or tape. You can then use it as the nucleus of your own graphics programs.

;
; Equates
;
; Without these, the program won't assemble properly
;
ICCOM = $342		; the COMMAND byte in the IOCB
ICBAL = $344		; the low byte of the buffer address (filename)
ICBLL = $348		; the low byte of the buffer length
ICAX1 = $34A		; auxiliary byte 1: type
ICAX2 = $34B		; auxiliary byte 2: mode
;
CIO = $E456		; Central Input/Output routine
ROWCRS = 84		; ROW CuRSor—y position
COLCRS = 85		; COLumn CuRSor—x position
ATACHR = 763		; where line color goes for DRAWTO
;
; Now the working routines
;
; REMEMBER: these are only subroutines
; You must call them via JSR from your own code
;
;
; CLOSE channel
;
; Parameter: X register holds IOCB number
; On exit: Y register holds error code
;
CLOSE
 LDA #12		; close command
 STA ICCOM,X		; in place
 JMP CIO			; do the real work
;
;
; OPEN channel,type,mode,file
;
; Parameters: X register holds IOCB number
;		 A register holds type
;		 Y register holds mode
;		 the address of the file/device
;		 name must already be set up
;		 in the IOCB–
; On exit:		Y register holds error code
;
OPEN
 STA ICAX1,X		; the type value
 TYA STA ICAX2, X	; and the mode, if appropriate
 LDA #3		; OPEN command
 STA ICCOM, X	; in place
 JMP CIO		; the real work
;
;
;GRAPHICS mode
;
;Parameter: A register holds desired mode
;On exit: Y register holds error code
;
GRAPHICS
PHA			; save the mode for a moment
LDX #$60		; always use IOCB #6
JSR CLOSE		; be sure it is closed
LDX #$60		; the same IOCB again
LDA #SNAME&$FF; the "S:" device name
STA ICBAL,X		; must be put in place
LDA #SNAME/$100	; before we go further
STA ICBAL + 1,X	; (take this part on faith)
PLA			; recover the GRAPHICS mode
TAY			; put it where OPEN wants it
AND #16 + 32	; isolate the text window and no-clear bits
EOR #16		; flip state of the text window bit
ORA #12		; allow both input and output
JMP OPEN		; do this part of the work
;
;
;PUT channel,byte
;
;Parameters: A register holds byte to output
;		 X register holds channel number
; On exit: Y register holds error code
;
PUT
TAY			; save the byte here for a moment
LDA #0
STA ICBLL,X		; $0000 to length
STA ICBLL + 1,X	; as noted last month
LDA #11		; the command value
STA ICCOM,X
TYA			; data byte back where CIO wants it
JMP CIO
;
;
; byte = GET( channel )
;
; Parameter: X register holds IOCB number
;On exit: A register holds byte from GET call
;
GET
 LDA #0
 STA ICBLL, X	; $0000 to length…
 STA ICBLL + 1,X	; as noted last month
 LDA #7		; the command value
 STA ICCOM, X	; where CIO wants it
 JMP CIO		; believe it or else, that's all
;
;
;PLOT x,y,color
;
; Parameters: A register holds color
;		 X register holds x location
;		 Y register holds y location
; NOTE: not for use with GR.8 or GR.24
;
PLOT
 STX COLCRS		;see my August column
 STY ROWCRS		;these are just POKEs
 LDX #$60	;the S: graphics channel
 JMP PUT		;color is already in A
;
;
;byte = LOCATE( x,y )
;
;Parameters: X register holds x location
;		 Y register holds y location
;On exit: A register holds color of point at (x,y)
;
LOCATE
 STX COLCRS		;again, see column
 STY ROWCRS		;from two months ago
 LDX #$60	;the S: graphics channel
 JMP GET		;color returned in A
;
;
;DRAWTO x, y, color
;
;Parameters: A register holds color
;		 X register holds x location
;	  Y register holds y location
; NOTE: not for use with GR.8 or GR.24
;
DRAWTO
 STX COLCRS		; once more: see the article
 STY ROWCRS		; from two months ago
 STA ATACHR		; location 763, also in that article
 LDX #$60	; again, we use IOCB #6
 LDA #17		; the XIO number for DRAWTO
 STA ICCOM,X		; is actually the command number
 JMP CIO		; and that's all we really need to do

Now that we have these routines, how do we use them? A full explanation would need at least the beginnings of a tutorial book. But here's a short example. First, a small program in BASIC:

100 GRAPHICS 3 + 16
110 COLOR 2 : PLOT 10, 10
120 COLOR 3 : PLOT 20, 20
130 COLOR 1 : PLOT 0, 15 : DRAWTO 30, 15
140 GOTO 140 : REM (just wait for RESET)

Now the same thing in machine language, using the routines of the program above. The only decision you will have to make is where in memory to place the assembled code. My first line reflects what should be a safe choice for most assemblers used in most 48K byte (or 64K byte) machines. If your assembler has a SIZE or MEMORY command, use it to get an idea of what is safe. In any case, LIST or SAVE your code to disk or tape before assembling, just in case.

		*= $6000		; my "usually safe" location
;
START LDA #3 + 16		; first
	 JSR GRAPHICS ; emulate GRAPHICS 19
;
	 LDX #10		; now do PLOT 10,10
	 LDY #10		;(x and y locations)
	 LDA #2		;with COLOR 2, a slight
	 JSR PLOT		;change from BASIC, but close
;
	 LDX #20		;similarly:
	 LDY #20		;we want PLOT 20,20
	 LDA #3		;with COLOR 3
	 JSR PLOT		;one call does it all
;
	 LDX #0		;last PLOT:
	 LDY #15		;PLOT 0,15
	 LDA #1		;with COLOR 1
	 JSR PLOT		;
;
	 LDX #30		;and now the DRAWTO:
	 LDY #15		;DRAWTO 30,15
	 LDA #1		;still with COLOR 1
	 JSR DRAWTO	;the routine does the work
;
LOOP1 JMP LOOP1		;(loop here until RESET is pressed)
;
;Append all of the code for all of; the subroutines here
;
;Your assembler may need .END or END as
; the very last line
;